News headline

1st half 2020

AU_timeline %>% 
  filter(date <= ymd(20200515)) %>%
  arrange(date) %>% 
  # filter(nchar(event) < 230) %>% 
  # filter(region != "VIC") %>% 
  mutate(rowid = as.numeric(rownames(.))) %>% 
  mutate(date_gap = as.numeric(date-lag(date))) %>% 
  mutate(nchar = nchar(event), 
         nchar_scaled = (nchar-min(nchar))/(max(nchar)-min(nchar)), 
         # point_position = 700 * nchar_scaled * (-1)^rowid,
         point_position = c(100,100,280,320,550,20,100,550,720,150,
                            240,880,400,300)*(-1)^rowid
         ) %>% 
  mutate(facet_var = quarter(date, with_year = T)) %>% 
  
  ggplot(aes(x=date, y=0)) + 
  geom_line() + 
  geom_point(aes(col=region)) +
  geom_segment(aes(x=date, xend=date, col=region,
                   y=0, yend=point_position)) +
  geom_point(aes(y=point_position, col=region), shape=1) +
  geom_text(aes(y=-10, 
                label=paste0(day(date), " ", 
                             month(date, label=T))), 
            angle=30, 
            vjust=1, hjust=1) + 
  geom_label(aes(label=str_wrap(paste0(date, ": ", event), nchar/1.8), alpha=.7,
                 # directions="y", min.segment.length = Inf,
                 x=date, y=point_position, col=region, vjust="outward")) +
  scale_x_date(date_breaks = "1 month", 
               date_labels = "%b %Y") + 
  # facet_wrap(~facet_var, strip.position="top",
  #            ncol = 1, scales = "free_x") +
  # coord_flip() +
  ylim(-1200,1200) + 
  coord_cartesian(clip = "off") + 
  labs(subtitle = "AU/NSW Covid-19 timeline, 1st half 2020") +
  theme_void(base_size = 23) +
  theme(legend.position = "none", 
        # rect = element_rect(fill = "transparent"),
        plot.margin = unit(c(0, 2.3, 0, 2.3),"cm"),
        # plot.background = element_rect(fill = NULL)
        )

2nd half 2020

AU_timeline %>% 
  filter(date > ymd(20200515)) %>%
  arrange(date) %>% 
  # filter(nchar(event) < 230) %>% 
  # filter(region != "VIC") %>% 
  mutate(rowid = as.numeric(rownames(.))) %>% 
  mutate(date_gap = as.numeric(date-lag(date))) %>% 
  mutate(nchar = nchar(event), 
         nchar_scaled = (nchar-min(nchar))/(max(nchar)-min(nchar)), 
         # point_position = 700 * nchar_scaled * (-1)^rowid,
         point_position = c(50,100,280,420,550,720,100,550,720,150,
                            240,780,830,300)*(-1)^rowid
         ) %>% 
  mutate(facet_var = quarter(date, with_year = T)) %>% 
  
  ggplot(aes(x=date, y=0)) + 
  geom_line() + 
  geom_point(aes(col=region)) +
  geom_segment(aes(x=date, xend=date, col=region,
                   y=0, yend=point_position)) +
  geom_point(aes(y=point_position, col=region), shape=1) +
  geom_text(aes(y=-10, 
                label=paste0(day(date), " ", 
                             month(date, label=T))), 
            angle=30, 
            vjust=1, hjust=1) + 
  geom_label(aes(label=str_wrap(paste0(date, ": ", event), nchar/3), alpha=.7,
                 # directions="y", min.segment.length = Inf,
                 x=date, y=point_position, col=region, vjust="outward")) +
  scale_x_date(date_breaks = "1 month", 
               date_labels = "%b %Y") + 
  # facet_wrap(~facet_var, strip.position="top",
  #            ncol = 1, scales = "free_x") +
  # coord_flip() +
  ylim(-1200,1200) + 
  coord_cartesian(clip = "off") + 
  labs(subtitle = "AU/NSW Covid-19 timeline, 2nd half 2020") +
  theme_void(base_size = 23) +
  theme(legend.position = "none", 
        # rect = element_rect(fill = "transparent"),
        plot.margin = unit(c(0, 2.3, 0, 2.3),"cm"),
        # plot.background = element_rect(fill = NULL)
        )

Full

AU_timeline %>% 
  # filter(date >= ymd(20200220)) %>% 
  arrange(date) %>% 
  add_row(date = ymd(20200120), event="") %>%
  # add_row(date = ymd(20200220), event="") %>%
  add_row(date = ymd(20200331), event="") %>%
  add_row(date = ymd(20200401), event="") %>%
  add_row(date = ymd(20200630), event="") %>%
  add_row(date = ymd(20200701), event="") %>%
  add_row(date = ymd(20200930), event="") %>%
  add_row(date = ymd(20201001), event="") %>%
  # filter(nchar(event) < 230) %>% 
  # filter(region != "VIC") %>% 
  mutate(rowid = as.numeric(rownames(.))) %>% 
  mutate(date_gap = as.numeric(date-lag(date))) %>% 
  mutate(nchar = nchar(event), 
         nchar_scaled = (nchar-min(nchar))/(max(nchar)-min(nchar)), 
         point_position = 800 * nchar_scaled * (-1)^rowid,
         # point_position = c(100)*(-1)^rowid
         ) %>% 
  mutate(facet_var = quarter(date, with_year = T)) %>% 
  
  ggplot(aes(x=date, y=0)) + 
  geom_line() + 
  geom_point(aes(col=region)) +
  geom_segment(aes(x=date, xend=date, col=region,
                   y=0, yend=point_position)) +
  geom_point(aes(y=point_position, col=region), shape=1) +
  geom_text(aes(y=-10, 
                label=paste0(day(date), " ", 
                             month(date, label=T))), 
            angle=30, 
            vjust=1, hjust=1) + 
  geom_label(aes(label=str_wrap(paste0(date, ": ", event), nchar/2), alpha=.7,
                 # directions="y", min.segment.length = Inf,
                 x=date, y=point_position, col=region, vjust="outward")) +
  scale_x_date(date_breaks = "1 month", 
               date_labels = "%b %Y") + 
  facet_wrap(~facet_var, strip.position="top",
             ncol = 1, scales = "free_x") +
  # coord_flip() +
  ylim(-1200,1200) + 
  coord_cartesian(clip = "off") + 
  theme_void(base_size = 23) +
  theme(legend.position = "none", 
        # rect = element_rect(fill = "transparent"),
        plot.margin = unit(c(0, 2.3, 0, 2.3),"cm"),
        # plot.background = element_rect(fill = NULL)
        )

Time series

Daily

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(notification_date) %>% 
  ggplot(aes(x=notification_date , y=n)) + 
  # geom_point() + 
  geom_line() + 
  ylab("Count of cases") + 
  labs(subtitle = "Daily new confirmed Covid-19 cases (SYD metro)") + 
  annotate("text", x=ymd(20200505), y=110, size=3.3, col="darkred", 
           label="1st outbreak \n (Bondi beach, \nSouth Eastern \nSydney)") + 
  annotate("text", x=ymd(20200815), y=30, size=3.3, col="darkred", 
           label="2nd outbreak \n (Liverpool, Western Sydney)") + 
  annotate("text", x=ymd(20210101), y=40, size=3.3, col="darkred", 
           label="3rd outbreak \n (Avalon beach, Northern Sydney)") + 
  ggl()

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(lhd_2010_name, notification_date) %>% 
  ggplot(aes(x=notification_date , y=n, col=lhd_2010_name)) + 
  # geom_point() + 
  geom_line() + 
  # facet_wrap(~lhd_2010_name) + 
  labs(subtitle = "Daily new confirmed Covid-19 cases (SYD)") + 
  ggl(lp = "right")

Cumulative

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(lhd_2010_name = ifelse(lhd_2010_name == "Sydney", "Metro Sydney", 
                                lhd_2010_name)) %>% 
  # mutate(lhd_2010_name = ifelse(is.na(lhd_2010_name), "Unknown", lhd_2010_name)) %>%
  count(lhd_2010_name, notification_date) %>% 
  group_by(lhd_2010_name) %>% 
  mutate(days_since_first_case = notification_date - min(notification_date)) %>% 
  mutate(accumulated_cases = cumsum(n)) %>% 
  mutate(lab = ifelse(notification_date == max(notification_date, na.rm=T), 
                      lhd_2010_name, NA)) %>% 
  
  ggplot(aes(x=days_since_first_case , y=accumulated_cases, col=lhd_2010_name)) + 
  # geom_point() + 
  geom_line() + 
  geom_text_repel(aes(label=lab), size=4, hjust=-.1, min.segment.length = 10) + 
  # facet_wrap(~lhd_2010_name) + 
  labs(subtitle = "Accumulated confirmed Covid-19 cases (SYD), by region") + 
  xlim(c(0,550)) +
  ggl(lp = "none") 

confirmed_cases %>% 
  mutate(lhd_2010_name = ifelse(lhd_2010_name == "Sydney", "Metro Sydney", 
                                lhd_2010_name)) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  # filter(lhd_2010_name %in% c("South Eastern Sydney", 
  #                          "Northern Sydney", 
  #                          "Western Sydney", 
  #                          "South Western Sydney", 
  #                          "Sydney") | is.na(lhd_2010_name)) %>% 
  count(lhd_2010_name, postcode, notification_date) %>% 
  group_by(lhd_2010_name, postcode) %>% 
  mutate(days_since_first_case = notification_date - min(notification_date)) %>% 
  mutate(accumulated_cases = cumsum(n)) %>% 
  mutate(lab=ifelse(notification_date == max(notification_date), postcode, NA)) %>% 
  
  ggplot(aes(x=days_since_first_case , y=accumulated_cases, 
             group=postcode,
             col=lhd_2010_name)) + 
  # geom_point() + 
  geom_line() + 
  geom_text(aes(label=lab), size=3, hjust="outward") + 
  facet_wrap(~lhd_2010_name) +
  labs(subtitle = "Accumulated confirmed Covid-19 cases (Sydney), by postcode") + 
  xlim(c(0,550)) +
  ggl(lp = "none", )

Map

Looks like each postcode (POA) can only belong to one LGA, which is not the case for SA2

confirmed_cases %>% 
  distinct(postcode, lga_name19) %>% 
  count(postcode) %>% 
  summarise(max(n)) %>% 
  pull()
[1] 1

LGA

confirmed_cases %>% 
  filter(lga_name19 %in% SYD_LGA$LGA_NAME19) %>% 
  count(lga_name19, name="Total_cases") %>% 
  rename(LGA_NAME19 = lga_name19) %>% 
  mutate(LGA_NAME19 = fct_reorder(LGA_NAME19, Total_cases)) %>% 
  plot_map_TL(SYD_LGA, "LGA_NAME19", "Total_cases", 
           "Total Covid-19 cases by LGA (SYD Metro)", show_count = T)

POA

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(postcode, name="Total_cases") %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "Total_cases", 
           "Total Covid-19 cases by POA (SYD Metro)", 
           show_count = T, label_size = 2)

confirmed_cases %>% 
  filter(!(postcode %in% c(2026, 2145, 2170))) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(postcode, name="Total_cases") %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "Total_cases", 
           "Total Covid-19 cases by POA (SYD Metro), excluding top 3 POA", 
           show_count = T, label_size = 2)

Note

Northern Beaches has many postcodes which result in more diluted choropleth by POA.

confirmed_cases %>% 
  distinct(lga_name19, postcode) %>% 
  count(lga_name19, name="Number_of_postcodes") %>% 
  left_join(confirmed_cases %>% count(lga_name19, name="Total_cases"), 
            by="lga_name19") %>% 
  slice_max(n=30, order_by = Total_cases) %>% 
  gather(key, value, -lga_name19) %>% 
  ggplot(aes(x=reorder(lga_name19, value), y=value)) + 
  geom_col() + 
  facet_wrap(~key, scales = "free_x") + 
  coord_flip() + 
  xlab("") + ylab("") + 
  ggl()

Map overtime cumulative

By quarter

Accumulated cases

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(year_quarter = paste(year(notification_date), "Q",
                             quarter(notification_date), sep="-")) %>% 
  count(year_quarter, postcode, name="Total_cases") %>% 
  complete(year_quarter, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(year_quarter) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, 
                                                    na.rm=T))) %>% 
  mutate(facet_var = paste0(year_quarter, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  
  plot_map_TL(rmapshaper::ms_simplify(
    SYD_POA[SYD_POA$POA_NAME16 %in% as.character(
      confirmed_cases$postcode) ,], .01), 
              "POA_NAME16", "Accumulated_cases", 
           "Total Covid-19 cases by POA (SYD Metro)", 
           return_obj="map") + 
  facet_wrap(~facet_var) + 
  theme(legend.position = "top")

Accumulated share

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(year_quarter = paste(year(notification_date), "Q",
                             quarter(notification_date), sep="-")) %>% 
  count(year_quarter, postcode, name="Total_cases") %>% 
  complete(year_quarter, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(year_quarter) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, 
                                                    na.rm=T))) %>%
  mutate(facet_var = paste0(year_quarter, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  
  plot_map_TL(rmapshaper::ms_simplify(
    SYD_POA[SYD_POA$POA_NAME16 %in% as.character(
      confirmed_cases$postcode) ,], .01), 
              "POA_NAME16", "Accumulated_share", 
           "Total Covid-19 cases by POA (SYD Metro)", 
           return_obj="map") + 
  facet_wrap(~facet_var) + 
  theme(legend.position = "top")

By week Mar-May 2020

Accumulated cases

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  filter(year(notification_date) == 2020, 
         # month(notification_date) %in% 3:5, 
         isoweek(notification_date) %in% 10:23) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(isoweek = isoweek(notification_date)) %>% 
  count(isoweek, postcode, name="Total_cases") %>% 
  complete(isoweek, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(isoweek) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, 
                                                    na.rm=T))) %>%
  mutate(facet_var = paste0("week ", isoweek, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  ungroup() %>% 
  filter(!is.na(isoweek)) %>% 
  
  plot_map_TL(rmapshaper::ms_simplify(SYD_POA, .01), 
              "POA_NAME16", "Accumulated_cases", 
              "Total Covid-19 cases by POA (SYD Metro)", 
              return_obj="map") + 
  facet_wrap(~facet_var)

Accumulated share

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  filter(year(notification_date) == 2020, 
         # month(notification_date) %in% 3:5, 
         isoweek(notification_date) %in% 10:23) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(isoweek = isoweek(notification_date)) %>% 
  count(isoweek, postcode, name="Total_cases") %>% 
  complete(isoweek, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(isoweek) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, na.rm=T))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  mutate(facet_var = paste0("week ", isoweek, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  ungroup() %>% 
  filter(!is.na(isoweek)) %>% 
  
  plot_map_TL(rmapshaper::ms_simplify(SYD_POA, .01), 
              "POA_NAME16", "Accumulated_share", 
              "Total Covid-19 cases by POA (SYD Metro)", 
              return_obj="map") + 
  facet_wrap(~facet_var)

Distribution of share overtime

By quarter

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(year_quarter = paste(year(notification_date), "Q",
                             quarter(notification_date), sep="-")) %>% 
  count(year_quarter, postcode, name="Total_cases") %>% 
  complete(year_quarter, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  ungroup() %>% 
  complete(year_quarter, postcode) %>% 
  replace_na(list(Accumulated_cases=0)) %>% 
  group_by(year_quarter) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, na.rm=T))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  ungroup() %>% 
  
  ggplot(aes(x=year_quarter, y=Accumulated_cases, 
             fill=Accumulated_cases > 50,
             group=as.factor(POA_NAME16))) + 
  geom_col(col="white", size=.1) + 
  ggf(fc = DC[2:1]) + 
  ggl("top", lt = T)

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(year_quarter = paste(year(notification_date), "Q",
                             quarter(notification_date), sep="-")) %>% 
  count(year_quarter, postcode, name="Total_cases") %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  ungroup() %>% 
  complete(year_quarter, postcode) %>% 
  replace_na(list(Accumulated_cases=0)) %>% 
  group_by(year_quarter) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, na.rm=T))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  
  ggplot(aes(x=Accumulated_share, fill=as.factor(year_quarter))) + 
  # geom_density() + 
  geom_histogram() + 
  facet_wrap(~year_quarter, nrow = 1) + 
  xlim(0,.03) + 
  ylim(0,40) +
  ggl("none")

By week

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  filter(year(notification_date) == 2020, 
         # month(notification_date) %in% 3:5, 
         isoweek(notification_date) %in% 10:23) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(isoweek = isoweek(notification_date)) %>% 
  count(isoweek, postcode, name="Total_cases") %>% 
  complete(isoweek, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(isoweek) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, 
                                                    na.rm=T))) %>%
  mutate(facet_var = paste0("week ", isoweek, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  ungroup() %>% 
  filter(!is.na(isoweek)) %>% 
  
  ggplot(aes(x=isoweek, y=Accumulated_cases, 
             fill=Accumulated_cases > 20,
             group=as.factor(POA_NAME16))) + 
  geom_col(col="white", size=.1) + 
  ggx(round, pbn=12) +
  ggf(fc = DC[2:1]) + 
  ggl("top", lt = T)

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  filter(year(notification_date) == 2020, 
         # month(notification_date) %in% 3:5, 
         isoweek(notification_date) %in% 10:23) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(isoweek = isoweek(notification_date)) %>% 
  count(isoweek, postcode, name="Total_cases") %>% 
  complete(isoweek, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(isoweek) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, 
                                                    na.rm=T))) %>%
  mutate(facet_var = paste0("week ", isoweek, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  ungroup() %>% 
  filter(!is.na(isoweek)) %>% 
  
  ggplot(aes(x=Accumulated_share, fill=as.factor(isoweek))) + 
  # geom_density() + 
  geom_histogram() + 
  facet_wrap(~isoweek, nrow = 3, labeller = "label_both") + 
  xlim(0,.03) + 
  ylim(0,40) +
  ggl("none")

Local POI

Public transport

confirmed_cases %>% 
    filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
    count(postcode, name="Total_cases") %>% 
    rename(POA_NAME16 = postcode) %>% 
    mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
    plot_map_TL(SYD_POA, "POA_NAME16", "Total_cases", 
                "Total Covid-19 cases by POA (SYD Metro), with public transport", 
                show_count = T, label_size = 2, return_obj = "map") +
  
  # geom_map(inherit.aes = FALSE, alpha=.85,
  #          aes(map_id = id), map = tidy(SYD_POA), 
  #          col="grey50", size=.3, fill="white") +
  geom_line(data = SYD_trains, 
            aes(x=lon, y=lat, col="Train",
                group = `Railway line(s)`),
            size=.8) +
  geom_line(data = SYD_ferries, 
            aes(x=lon, y=lat, col="Ferry"),
             size=.8) +
  geom_line(data = SYD_lightrails, 
            aes(x=lon, y=lat, col="Lightrail"),
             size=.8) +
  geom_line(data = SYD_metro, 
            aes(x=lon, y=lat, col="Metro"),
             size=.8) +
  ggc(c("deepskyblue", "red", "darkgreen", "orange")) + 
  guides(col=guide_legend(title="Transport_mode")) + 
  expand_limits(x = tidy(SYD_POA)$long, y = tidy(SYD_POA)$lat) +
  coord_cartesian(xlim = c(150.7, 151.48), ylim = c(-34.1, -33.5)) +
  theme_void() +
  theme(legend.position = c(.9,.35))

Hospitals, Schools, Supermarket

bind_rows(
  SYD_shops %>% select(lon, lat) %>% 
    rename(Long = lon, Lat = lat) %>% mutate(obj = "Shopping centres"), 
  SYD_supermarkets %>% select(lon, lat) %>% 
    rename(Long = lon, Lat = lat) %>% mutate(obj = "Supermarkets"), 
  SYD_hospitals %>% select(Longitude, Latitude) %>% 
    rename(Long = Longitude, Lat = Latitude) %>% mutate(obj = "Hospitals"), 
  rbind(SYD_sschools %>% select(Long, Lat),
        SYD_pschools %>% select(Long, Lat)) %>% mutate(obj = "Schools")
) %>% 
  ggplot() +  
  geom_map(data = SYD_POA, inherit.aes = FALSE, alpha=.85,
           aes(map_id = id), map = tidy(SYD_POA), 
           col="grey50", size=.2, fill="white") +
  geom_jitter(aes(x=Long, y=Lat, col=obj), size=.8, alpha=.5) + 
  stat_density2d(aes(x=Long, y=Lat, 
                     fill=..level.., alpha=..level.., col=obj),
                 binwidth = 1.2, geom="polygon", size=.23) + 
  facet_wrap(~obj) +
  expand_limits(x = tidy(SYD_POA)$long, y = tidy(SYD_POA)$lat) +
  xlim(150.7,151.48) + ylim(-34.1,-33.5) +
  scale_fill_gradient(low="white", high=DC[7]) + 
  scale_alpha_continuous(range = c(0,.3)) + 
  ggc(fc = c("darkred", "deepskyblue", "black", "darkgreen")) + 
  theme_void() +
  theme(legend.position = "none", 
        legend.title = element_blank(), 
        strip.text = element_text(size=15))

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(postcode, name="Total_cases") %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "Total_cases", 
              "Total Covid-19 cases by POA (SYD Metro), with hospitals, schools & supermarkets", 
              show_count = T, label_size = 2, return_obj = "map") +
  
  # geom_map(data = SYD_POA, inherit.aes = FALSE, alpha=.85,
  #          aes(map_id = id), map = tidy(SYD_POA), 
  #          col="grey50", size=.3, fill="white") +
  geom_jitter(data = bind_rows(
    SYD_shops %>% select(lon, lat) %>% 
      rename(Long = lon, Lat = lat) %>% mutate(obj = "Shopping centres"), 
    SYD_supermarkets %>% select(lon, lat) %>% 
      rename(Long = lon, Lat = lat) %>% mutate(obj = "Supermarkets"), 
    SYD_hospitals %>% select(Longitude, Latitude) %>% 
      rename(Long = Longitude, Lat = Latitude) %>% mutate(obj = "Hospitals"), 
    rbind(SYD_sschools %>% select(Long, Lat),
          SYD_pschools %>% select(Long, Lat)) %>% mutate(obj = "Schools")
  ), 
  size = 1, alpha = .3, aes(x=Long, y=Lat,col=obj)) +
  expand_limits(x = tidy(SYD_POA)$long, y = tidy(SYD_POA)$lat) +
  xlim(150.7,151.48) + ylim(-34.1,-33.5) +
  # scale_fill_gradient(low="white", high=DC[7]) + 
  scale_alpha_continuous(range = c(0,.3)) + 
  ggc(fc = c("darkred", "darkblue", "darkorange", "darkgreen")) + 
  guides(color = guide_legend(override.aes = list(size=3), 
                              title="POI")) + 
  theme_void() +
  theme(legend.position = c(.9,.25), 
        # legend.title = element_blank(), 
        strip.text = element_text(size=15))

POI combined

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(postcode, name="Total_cases") %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "Total_cases", 
              "Total Covid-19 cases by POA (SYD Metro), with hospitals, schools & supermarkets", 
              show_count = T, label_size = 2, return_obj = "map") +
  geom_line(data = SYD_trains, 
            aes(x=lon, y=lat, col="Train",
                group = `Railway line(s)`),
            size=.8) +
  geom_line(data = SYD_ferries, 
            aes(x=lon, y=lat, col="Ferry"),
             size=.8) +
  geom_line(data = SYD_lightrails, 
            aes(x=lon, y=lat, col="Lightrail"),
             size=.8) +
  geom_line(data = SYD_metro, 
            aes(x=lon, y=lat, col="Metro"),
             size=.8) +
  
  # geom_map(data = SYD_POA, inherit.aes = FALSE, alpha=.85,
  #          aes(map_id = id), map = tidy(SYD_POA), 
  #          col="grey50", size=.3, fill="white") +
  geom_jitter(data = bind_rows(
    SYD_shops %>% select(lon, lat) %>% 
      rename(Long = lon, Lat = lat) %>% mutate(obj = "Shopping centres"), 
    SYD_supermarkets %>% select(lon, lat) %>% 
      rename(Long = lon, Lat = lat) %>% mutate(obj = "Supermarkets"), 
    SYD_hospitals %>% select(Longitude, Latitude) %>% 
      rename(Long = Longitude, Lat = Latitude) %>% mutate(obj = "Hospitals"), 
    rbind(SYD_sschools %>% select(Long, Lat),
          SYD_pschools %>% select(Long, Lat)) %>% mutate(obj = "Schools")
  ), 
  size = 1, alpha = .3, aes(x=Long, y=Lat,col=obj)) +
  expand_limits(x = tidy(SYD_POA)$long, y = tidy(SYD_POA)$lat) +
  xlim(150.7,151.48) + ylim(-34.1,-33.5) +
  # scale_fill_gradient(low="white", high=DC[7]) + 
  scale_alpha_continuous(range = c(0,.3)) + 
  ggc(fc = c("darkred", "darkblue", "darkorange", "darkgreen", 
             "darkblue", "red", "darkgreen", "orange")) + 
  guides(color = guide_legend(override.aes = list(size=3), 
                              title="POI")) + 
  theme_void() +
  theme(legend.position = c(.9,.4), 
        # legend.title = element_blank(), 
        strip.text = element_text(size=15))

POI count QA

Hospital

n_poi_by_POA %>% 
  filter(POA_NAME16 != "Unknown") %>% 
  # gather(key, value, -POA_NAME16) %>% 
  select(POA_NAME16, n_hospitals) %>% 
  mutate(POA_NAME16 = fct_reorder(POA_NAME16, n_hospitals)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "n_hospitals", 
              "Number of hospitals by POA", 
              show_count = T, fill_col = "darkred")

Schools

n_poi_by_POA %>% 
  filter(POA_NAME16 != "Unknown") %>% 
  # gather(key, value, -POA_NAME16) %>% 
  select(POA_NAME16, n_schools) %>% 
  mutate(POA_NAME16 = fct_reorder(POA_NAME16, n_schools)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "n_schools", 
              "Number of schools by POA", 
              show_count = T, fill_col = "deepskyblue")

Supermarkets

n_poi_by_POA %>% 
  filter(POA_NAME16 != "Unknown") %>% 
  # gather(key, value, -POA_NAME16) %>% 
  select(POA_NAME16, n_supermarkets) %>% 
  mutate(POA_NAME16 = fct_reorder(POA_NAME16, n_supermarkets)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "n_supermarkets", 
              "Number of supermarkets by POA", 
              show_count = T, fill_col = "darkgreen")

Shopping centres

n_poi_by_POA %>% 
  filter(POA_NAME16 != "Unknown") %>% 
  # gather(key, value, -POA_NAME16) %>% 
  select(POA_NAME16, n_shoppingCentres) %>% 
  mutate(POA_NAME16 = fct_reorder(POA_NAME16, n_shoppingCentres)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "n_shoppingCentres", 
              "Number of shopping centres by POA", 
              show_count = T, fill_col = "black")

Public transports

n_poi_by_POA %>% 
  filter(POA_NAME16 != "Unknown") %>% 
  # gather(key, value, -POA_NAME16) %>% 
  select(POA_NAME16, n_publicTransports ) %>% 
  mutate(POA_NAME16 = fct_reorder(POA_NAME16, n_publicTransports )) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "n_publicTransports", 
              "Number of public transports by POA", 
              show_count = T, fill_col = "darkorange")

Gravity

South Eastern SYD (2026)

(
plot_gravity_map_TL(n_poi_by_POA, "2026", "n_hospitals") + 
  xlim(151.1,151.33) + ylim(-34,-33.7) | 
plot_gravity_map_TL(n_poi_by_POA, "2026", "n_schools") + 
  xlim(151.1,151.33) + ylim(-34,-33.7) |
plot_gravity_map_TL(n_poi_by_POA, "2026", "n_supermarkets") + 
  xlim(151.1,151.33) + ylim(-34,-33.7)
) /
(
plot_gravity_map_TL(n_poi_by_POA, "2026", "n_shoppingCentres") + 
  xlim(151.1,151.33) + ylim(-34,-33.7) | 
plot_gravity_map_TL(n_poi_by_POA, "2026", "n_publicTransports") + 
  xlim(151.1,151.33) + ylim(-34,-33.7) | 
n_poi_by_POA %>% 
  mutate(combined_index = 
           normalised_n_hospitals +
           normalised_n_schools +
           normalised_n_supermarkets +
           normalised_n_shoppingCentres +
           normalised_n_publicTransports
  ) %>% plot_gravity_map_TL("2026", "combined_index") + 
  xlim(151.1,151.33) + ylim(-34,-33.7)
)

Western SYD (2145)

(
plot_gravity_map_TL(n_poi_by_POA, "2145", "n_hospitals") | 
plot_gravity_map_TL(n_poi_by_POA, "2145", "n_schools") |
plot_gravity_map_TL(n_poi_by_POA, "2145", "n_supermarkets")
) /
(
plot_gravity_map_TL(n_poi_by_POA, "2145", "n_shoppingCentres") | 
plot_gravity_map_TL(n_poi_by_POA, "2145", "n_publicTransports") | 
n_poi_by_POA %>% 
  mutate(combined_index = 
           normalised_n_hospitals +
           normalised_n_schools +
           normalised_n_supermarkets +
           normalised_n_shoppingCentres +
           normalised_n_publicTransports
  ) %>% plot_gravity_map_TL("2145", "combined_index")
)

Nothern SYD (2107)

(
plot_gravity_map_TL(n_poi_by_POA, "2107", "n_hospitals") + 
  xlim(151,151.4) + ylim(-33.9,-33.5) | 
plot_gravity_map_TL(n_poi_by_POA, "2107", "n_schools") + 
  xlim(151,151.4) + ylim(-33.9,-33.5) |
plot_gravity_map_TL(n_poi_by_POA, "2107", "n_supermarkets") + 
  xlim(151,151.4) + ylim(-33.9,-33.5)
) /
(
plot_gravity_map_TL(n_poi_by_POA, "2107", "n_shoppingCentres") + 
  xlim(151,151.4) + ylim(-33.9,-33.5) | 
plot_gravity_map_TL(n_poi_by_POA, "2107", "n_publicTransports") + 
  xlim(151,151.4) + ylim(-33.9,-33.5) | 
n_poi_by_POA %>% 
  mutate(combined_index = 
           normalised_n_hospitals +
           normalised_n_schools +
           normalised_n_supermarkets +
           normalised_n_shoppingCentres +
           normalised_n_publicTransports
  ) %>% plot_gravity_map_TL("2107", "combined_index") + 
  xlim(151,151.4) + ylim(-33.9,-33.5)
)

LS0tDQp0aXRsZTogIlNZRCBDb3ZpZC0xOSBjYXNlcyBFREEiDQphdXRob3I6ICJUb255IExpdSINCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBoaWdobGlnaHQ6IHplbmJ1cm4NCiAgICB0aGVtZTogZmxhdGx5DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IG5vDQogIHBkZl9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KIyBzb3VyY2UoInV0aWxpdHkuUiIpDQpzb3VyY2UoIlJfZnVuY3Rpb25zLlIiKQ0Kc291cmNlKCJSX2RhdGFfcHJlcG9jZXNzaW5nLlIiKQ0KDQpvcHRpb25zKHNjaXBlbj05OTksIGV4cHJlc3Npb25zPTUwMDAwLCANCiAgICAgICAgRFQub3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDgsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHNjcm9sbFggPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBkb20gPSAnQmZydGlwJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgYnV0dG9ucyA9IGMoJ2NvcHknLCAnY3N2JywgJ2V4Y2VsJywgJ3BkZicsICdwcmludCcpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgYXV0b1dpZHRoID0gVFJVRSkpIA0KDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFQsIG1lc3NhZ2U9Riwgd2FybmluZz1GLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTQpDQprbml0cjo6b3B0c19rbml0JHNldChkZXYuYXJncyA9IGxpc3QodHlwZSA9ICJjYWlybyIpLCBwcm9ncmVzcz1GQUxTRSkNCmBgYA0KDQojIE5ld3MgaGVhZGxpbmUgDQojIyAxc3QgaGFsZiAyMDIwDQoNCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTJ9DQpBVV90aW1lbGluZSAlPiUgDQogIGZpbHRlcihkYXRlIDw9IHltZCgyMDIwMDUxNSkpICU+JQ0KICBhcnJhbmdlKGRhdGUpICU+JSANCiAgIyBmaWx0ZXIobmNoYXIoZXZlbnQpIDwgMjMwKSAlPiUgDQogICMgZmlsdGVyKHJlZ2lvbiAhPSAiVklDIikgJT4lIA0KICBtdXRhdGUocm93aWQgPSBhcy5udW1lcmljKHJvd25hbWVzKC4pKSkgJT4lIA0KICBtdXRhdGUoZGF0ZV9nYXAgPSBhcy5udW1lcmljKGRhdGUtbGFnKGRhdGUpKSkgJT4lIA0KICBtdXRhdGUobmNoYXIgPSBuY2hhcihldmVudCksIA0KICAgICAgICAgbmNoYXJfc2NhbGVkID0gKG5jaGFyLW1pbihuY2hhcikpLyhtYXgobmNoYXIpLW1pbihuY2hhcikpLCANCiAgICAgICAgICMgcG9pbnRfcG9zaXRpb24gPSA3MDAgKiBuY2hhcl9zY2FsZWQgKiAoLTEpXnJvd2lkLA0KICAgICAgICAgcG9pbnRfcG9zaXRpb24gPSBjKDEwMCwxMDAsMjgwLDMyMCw1NTAsMjAsMTAwLDU1MCw3MjAsMTUwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDI0MCw4ODAsNDAwLDMwMCkqKC0xKV5yb3dpZA0KICAgICAgICAgKSAlPiUgDQogIG11dGF0ZShmYWNldF92YXIgPSBxdWFydGVyKGRhdGUsIHdpdGhfeWVhciA9IFQpKSAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHg9ZGF0ZSwgeT0wKSkgKyANCiAgZ2VvbV9saW5lKCkgKyANCiAgZ2VvbV9wb2ludChhZXMoY29sPXJlZ2lvbikpICsNCiAgZ2VvbV9zZWdtZW50KGFlcyh4PWRhdGUsIHhlbmQ9ZGF0ZSwgY29sPXJlZ2lvbiwNCiAgICAgICAgICAgICAgICAgICB5PTAsIHllbmQ9cG9pbnRfcG9zaXRpb24pKSArDQogIGdlb21fcG9pbnQoYWVzKHk9cG9pbnRfcG9zaXRpb24sIGNvbD1yZWdpb24pLCBzaGFwZT0xKSArDQogIGdlb21fdGV4dChhZXMoeT0tMTAsIA0KICAgICAgICAgICAgICAgIGxhYmVsPXBhc3RlMChkYXkoZGF0ZSksICIgIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vbnRoKGRhdGUsIGxhYmVsPVQpKSksIA0KICAgICAgICAgICAgYW5nbGU9MzAsIA0KICAgICAgICAgICAgdmp1c3Q9MSwgaGp1c3Q9MSkgKyANCiAgZ2VvbV9sYWJlbChhZXMobGFiZWw9c3RyX3dyYXAocGFzdGUwKGRhdGUsICI6ICIsIGV2ZW50KSwgbmNoYXIvMS44KSwgYWxwaGE9LjcsDQogICAgICAgICAgICAgICAgICMgZGlyZWN0aW9ucz0ieSIsIG1pbi5zZWdtZW50Lmxlbmd0aCA9IEluZiwNCiAgICAgICAgICAgICAgICAgeD1kYXRlLCB5PXBvaW50X3Bvc2l0aW9uLCBjb2w9cmVnaW9uLCB2anVzdD0ib3V0d2FyZCIpKSArDQogIHNjYWxlX3hfZGF0ZShkYXRlX2JyZWFrcyA9ICIxIG1vbnRoIiwgDQogICAgICAgICAgICAgICBkYXRlX2xhYmVscyA9ICIlYiAlWSIpICsgDQogICMgZmFjZXRfd3JhcCh+ZmFjZXRfdmFyLCBzdHJpcC5wb3NpdGlvbj0idG9wIiwNCiAgIyAgICAgICAgICAgIG5jb2wgPSAxLCBzY2FsZXMgPSAiZnJlZV94IikgKw0KICAjIGNvb3JkX2ZsaXAoKSArDQogIHlsaW0oLTEyMDAsMTIwMCkgKyANCiAgY29vcmRfY2FydGVzaWFuKGNsaXAgPSAib2ZmIikgKyANCiAgbGFicyhzdWJ0aXRsZSA9ICJBVS9OU1cgQ292aWQtMTkgdGltZWxpbmUsIDFzdCBoYWxmIDIwMjAiKSArDQogIHRoZW1lX3ZvaWQoYmFzZV9zaXplID0gMjMpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCANCiAgICAgICAgIyByZWN0ID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwNCiAgICAgICAgcGxvdC5tYXJnaW4gPSB1bml0KGMoMCwgMi4zLCAwLCAyLjMpLCJjbSIpLA0KICAgICAgICAjIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gTlVMTCkNCiAgICAgICAgKQ0KYGBgDQoNCiMjIDJuZCBoYWxmIDIwMjANCg0KYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMn0NCkFVX3RpbWVsaW5lICU+JSANCiAgZmlsdGVyKGRhdGUgPiB5bWQoMjAyMDA1MTUpKSAlPiUNCiAgYXJyYW5nZShkYXRlKSAlPiUgDQogICMgZmlsdGVyKG5jaGFyKGV2ZW50KSA8IDIzMCkgJT4lIA0KICAjIGZpbHRlcihyZWdpb24gIT0gIlZJQyIpICU+JSANCiAgbXV0YXRlKHJvd2lkID0gYXMubnVtZXJpYyhyb3duYW1lcyguKSkpICU+JSANCiAgbXV0YXRlKGRhdGVfZ2FwID0gYXMubnVtZXJpYyhkYXRlLWxhZyhkYXRlKSkpICU+JSANCiAgbXV0YXRlKG5jaGFyID0gbmNoYXIoZXZlbnQpLCANCiAgICAgICAgIG5jaGFyX3NjYWxlZCA9IChuY2hhci1taW4obmNoYXIpKS8obWF4KG5jaGFyKS1taW4obmNoYXIpKSwgDQogICAgICAgICAjIHBvaW50X3Bvc2l0aW9uID0gNzAwICogbmNoYXJfc2NhbGVkICogKC0xKV5yb3dpZCwNCiAgICAgICAgIHBvaW50X3Bvc2l0aW9uID0gYyg1MCwxMDAsMjgwLDQyMCw1NTAsNzIwLDEwMCw1NTAsNzIwLDE1MCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAyNDAsNzgwLDgzMCwzMDApKigtMSlecm93aWQNCiAgICAgICAgICkgJT4lIA0KICBtdXRhdGUoZmFjZXRfdmFyID0gcXVhcnRlcihkYXRlLCB3aXRoX3llYXIgPSBUKSkgJT4lIA0KICANCiAgZ2dwbG90KGFlcyh4PWRhdGUsIHk9MCkpICsgDQogIGdlb21fbGluZSgpICsgDQogIGdlb21fcG9pbnQoYWVzKGNvbD1yZWdpb24pKSArDQogIGdlb21fc2VnbWVudChhZXMoeD1kYXRlLCB4ZW5kPWRhdGUsIGNvbD1yZWdpb24sDQogICAgICAgICAgICAgICAgICAgeT0wLCB5ZW5kPXBvaW50X3Bvc2l0aW9uKSkgKw0KICBnZW9tX3BvaW50KGFlcyh5PXBvaW50X3Bvc2l0aW9uLCBjb2w9cmVnaW9uKSwgc2hhcGU9MSkgKw0KICBnZW9tX3RleHQoYWVzKHk9LTEwLCANCiAgICAgICAgICAgICAgICBsYWJlbD1wYXN0ZTAoZGF5KGRhdGUpLCAiICIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb250aChkYXRlLCBsYWJlbD1UKSkpLCANCiAgICAgICAgICAgIGFuZ2xlPTMwLCANCiAgICAgICAgICAgIHZqdXN0PTEsIGhqdXN0PTEpICsgDQogIGdlb21fbGFiZWwoYWVzKGxhYmVsPXN0cl93cmFwKHBhc3RlMChkYXRlLCAiOiAiLCBldmVudCksIG5jaGFyLzMpLCBhbHBoYT0uNywNCiAgICAgICAgICAgICAgICAgIyBkaXJlY3Rpb25zPSJ5IiwgbWluLnNlZ21lbnQubGVuZ3RoID0gSW5mLA0KICAgICAgICAgICAgICAgICB4PWRhdGUsIHk9cG9pbnRfcG9zaXRpb24sIGNvbD1yZWdpb24sIHZqdXN0PSJvdXR3YXJkIikpICsNCiAgc2NhbGVfeF9kYXRlKGRhdGVfYnJlYWtzID0gIjEgbW9udGgiLCANCiAgICAgICAgICAgICAgIGRhdGVfbGFiZWxzID0gIiViICVZIikgKyANCiAgIyBmYWNldF93cmFwKH5mYWNldF92YXIsIHN0cmlwLnBvc2l0aW9uPSJ0b3AiLA0KICAjICAgICAgICAgICAgbmNvbCA9IDEsIHNjYWxlcyA9ICJmcmVlX3giKSArDQogICMgY29vcmRfZmxpcCgpICsNCiAgeWxpbSgtMTIwMCwxMjAwKSArIA0KICBjb29yZF9jYXJ0ZXNpYW4oY2xpcCA9ICJvZmYiKSArIA0KICBsYWJzKHN1YnRpdGxlID0gIkFVL05TVyBDb3ZpZC0xOSB0aW1lbGluZSwgMm5kIGhhbGYgMjAyMCIpICsNCiAgdGhlbWVfdm9pZChiYXNlX3NpemUgPSAyMykgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIA0KICAgICAgICAjIHJlY3QgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLA0KICAgICAgICBwbG90Lm1hcmdpbiA9IHVuaXQoYygwLCAyLjMsIDAsIDIuMyksImNtIiksDQogICAgICAgICMgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOVUxMKQ0KICAgICAgICApDQpgYGANCg0KIyMgRnVsbA0KDQpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTI1fQ0KQVVfdGltZWxpbmUgJT4lIA0KICAjIGZpbHRlcihkYXRlID49IHltZCgyMDIwMDIyMCkpICU+JSANCiAgYXJyYW5nZShkYXRlKSAlPiUgDQogIGFkZF9yb3coZGF0ZSA9IHltZCgyMDIwMDEyMCksIGV2ZW50PSIiKSAlPiUNCiAgIyBhZGRfcm93KGRhdGUgPSB5bWQoMjAyMDAyMjApLCBldmVudD0iIikgJT4lDQogIGFkZF9yb3coZGF0ZSA9IHltZCgyMDIwMDMzMSksIGV2ZW50PSIiKSAlPiUNCiAgYWRkX3JvdyhkYXRlID0geW1kKDIwMjAwNDAxKSwgZXZlbnQ9IiIpICU+JQ0KICBhZGRfcm93KGRhdGUgPSB5bWQoMjAyMDA2MzApLCBldmVudD0iIikgJT4lDQogIGFkZF9yb3coZGF0ZSA9IHltZCgyMDIwMDcwMSksIGV2ZW50PSIiKSAlPiUNCiAgYWRkX3JvdyhkYXRlID0geW1kKDIwMjAwOTMwKSwgZXZlbnQ9IiIpICU+JQ0KICBhZGRfcm93KGRhdGUgPSB5bWQoMjAyMDEwMDEpLCBldmVudD0iIikgJT4lDQogICMgZmlsdGVyKG5jaGFyKGV2ZW50KSA8IDIzMCkgJT4lIA0KICAjIGZpbHRlcihyZWdpb24gIT0gIlZJQyIpICU+JSANCiAgbXV0YXRlKHJvd2lkID0gYXMubnVtZXJpYyhyb3duYW1lcyguKSkpICU+JSANCiAgbXV0YXRlKGRhdGVfZ2FwID0gYXMubnVtZXJpYyhkYXRlLWxhZyhkYXRlKSkpICU+JSANCiAgbXV0YXRlKG5jaGFyID0gbmNoYXIoZXZlbnQpLCANCiAgICAgICAgIG5jaGFyX3NjYWxlZCA9IChuY2hhci1taW4obmNoYXIpKS8obWF4KG5jaGFyKS1taW4obmNoYXIpKSwgDQogICAgICAgICBwb2ludF9wb3NpdGlvbiA9IDgwMCAqIG5jaGFyX3NjYWxlZCAqICgtMSlecm93aWQsDQogICAgICAgICAjIHBvaW50X3Bvc2l0aW9uID0gYygxMDApKigtMSlecm93aWQNCiAgICAgICAgICkgJT4lIA0KICBtdXRhdGUoZmFjZXRfdmFyID0gcXVhcnRlcihkYXRlLCB3aXRoX3llYXIgPSBUKSkgJT4lIA0KICANCiAgZ2dwbG90KGFlcyh4PWRhdGUsIHk9MCkpICsgDQogIGdlb21fbGluZSgpICsgDQogIGdlb21fcG9pbnQoYWVzKGNvbD1yZWdpb24pKSArDQogIGdlb21fc2VnbWVudChhZXMoeD1kYXRlLCB4ZW5kPWRhdGUsIGNvbD1yZWdpb24sDQogICAgICAgICAgICAgICAgICAgeT0wLCB5ZW5kPXBvaW50X3Bvc2l0aW9uKSkgKw0KICBnZW9tX3BvaW50KGFlcyh5PXBvaW50X3Bvc2l0aW9uLCBjb2w9cmVnaW9uKSwgc2hhcGU9MSkgKw0KICBnZW9tX3RleHQoYWVzKHk9LTEwLCANCiAgICAgICAgICAgICAgICBsYWJlbD1wYXN0ZTAoZGF5KGRhdGUpLCAiICIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb250aChkYXRlLCBsYWJlbD1UKSkpLCANCiAgICAgICAgICAgIGFuZ2xlPTMwLCANCiAgICAgICAgICAgIHZqdXN0PTEsIGhqdXN0PTEpICsgDQogIGdlb21fbGFiZWwoYWVzKGxhYmVsPXN0cl93cmFwKHBhc3RlMChkYXRlLCAiOiAiLCBldmVudCksIG5jaGFyLzIpLCBhbHBoYT0uNywNCiAgICAgICAgICAgICAgICAgIyBkaXJlY3Rpb25zPSJ5IiwgbWluLnNlZ21lbnQubGVuZ3RoID0gSW5mLA0KICAgICAgICAgICAgICAgICB4PWRhdGUsIHk9cG9pbnRfcG9zaXRpb24sIGNvbD1yZWdpb24sIHZqdXN0PSJvdXR3YXJkIikpICsNCiAgc2NhbGVfeF9kYXRlKGRhdGVfYnJlYWtzID0gIjEgbW9udGgiLCANCiAgICAgICAgICAgICAgIGRhdGVfbGFiZWxzID0gIiViICVZIikgKyANCiAgZmFjZXRfd3JhcCh+ZmFjZXRfdmFyLCBzdHJpcC5wb3NpdGlvbj0idG9wIiwNCiAgICAgICAgICAgICBuY29sID0gMSwgc2NhbGVzID0gImZyZWVfeCIpICsNCiAgIyBjb29yZF9mbGlwKCkgKw0KICB5bGltKC0xMjAwLDEyMDApICsgDQogIGNvb3JkX2NhcnRlc2lhbihjbGlwID0gIm9mZiIpICsgDQogIHRoZW1lX3ZvaWQoYmFzZV9zaXplID0gMjMpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCANCiAgICAgICAgIyByZWN0ID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwNCiAgICAgICAgcGxvdC5tYXJnaW4gPSB1bml0KGMoMCwgMi4zLCAwLCAyLjMpLCJjbSIpLA0KICAgICAgICAjIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gTlVMTCkNCiAgICAgICAgKQ0KYGBgDQoNCiMgVGltZSBzZXJpZXMNCiMjIERhaWx5DQoNCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD00fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgY291bnQobm90aWZpY2F0aW9uX2RhdGUpICU+JSANCiAgZ2dwbG90KGFlcyh4PW5vdGlmaWNhdGlvbl9kYXRlICwgeT1uKSkgKyANCiAgIyBnZW9tX3BvaW50KCkgKyANCiAgZ2VvbV9saW5lKCkgKyANCiAgeWxhYigiQ291bnQgb2YgY2FzZXMiKSArIA0KICBsYWJzKHN1YnRpdGxlID0gIkRhaWx5IG5ldyBjb25maXJtZWQgQ292aWQtMTkgY2FzZXMgKFNZRCBtZXRybykiKSArIA0KICBhbm5vdGF0ZSgidGV4dCIsIHg9eW1kKDIwMjAwNTA1KSwgeT0xMTAsIHNpemU9My4zLCBjb2w9ImRhcmtyZWQiLCANCiAgICAgICAgICAgbGFiZWw9IjFzdCBvdXRicmVhayBcbiAoQm9uZGkgYmVhY2gsIFxuU291dGggRWFzdGVybiBcblN5ZG5leSkiKSArIA0KICBhbm5vdGF0ZSgidGV4dCIsIHg9eW1kKDIwMjAwODE1KSwgeT0zMCwgc2l6ZT0zLjMsIGNvbD0iZGFya3JlZCIsIA0KICAgICAgICAgICBsYWJlbD0iMm5kIG91dGJyZWFrIFxuIChMaXZlcnBvb2wsIFdlc3Rlcm4gU3lkbmV5KSIpICsgDQogIGFubm90YXRlKCJ0ZXh0IiwgeD15bWQoMjAyMTAxMDEpLCB5PTQwLCBzaXplPTMuMywgY29sPSJkYXJrcmVkIiwgDQogICAgICAgICAgIGxhYmVsPSIzcmQgb3V0YnJlYWsgXG4gKEF2YWxvbiBiZWFjaCwgTm9ydGhlcm4gU3lkbmV5KSIpICsgDQogIGdnbCgpDQpgYGANCg0KYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTV9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBjb3VudChsaGRfMjAxMF9uYW1lLCBub3RpZmljYXRpb25fZGF0ZSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9bm90aWZpY2F0aW9uX2RhdGUgLCB5PW4sIGNvbD1saGRfMjAxMF9uYW1lKSkgKyANCiAgIyBnZW9tX3BvaW50KCkgKyANCiAgZ2VvbV9saW5lKCkgKyANCiAgIyBmYWNldF93cmFwKH5saGRfMjAxMF9uYW1lKSArIA0KICBsYWJzKHN1YnRpdGxlID0gIkRhaWx5IG5ldyBjb25maXJtZWQgQ292aWQtMTkgY2FzZXMgKFNZRCkiKSArIA0KICBnZ2wobHAgPSAicmlnaHQiKQ0KYGBgDQoNCiMjIEN1bXVsYXRpdmUNCg0KYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTV9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBtdXRhdGUobGhkXzIwMTBfbmFtZSA9IGlmZWxzZShsaGRfMjAxMF9uYW1lID09ICJTeWRuZXkiLCAiTWV0cm8gU3lkbmV5IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxoZF8yMDEwX25hbWUpKSAlPiUgDQogICMgbXV0YXRlKGxoZF8yMDEwX25hbWUgPSBpZmVsc2UoaXMubmEobGhkXzIwMTBfbmFtZSksICJVbmtub3duIiwgbGhkXzIwMTBfbmFtZSkpICU+JQ0KICBjb3VudChsaGRfMjAxMF9uYW1lLCBub3RpZmljYXRpb25fZGF0ZSkgJT4lIA0KICBncm91cF9ieShsaGRfMjAxMF9uYW1lKSAlPiUgDQogIG11dGF0ZShkYXlzX3NpbmNlX2ZpcnN0X2Nhc2UgPSBub3RpZmljYXRpb25fZGF0ZSAtIG1pbihub3RpZmljYXRpb25fZGF0ZSkpICU+JSANCiAgbXV0YXRlKGFjY3VtdWxhdGVkX2Nhc2VzID0gY3Vtc3VtKG4pKSAlPiUgDQogIG11dGF0ZShsYWIgPSBpZmVsc2Uobm90aWZpY2F0aW9uX2RhdGUgPT0gbWF4KG5vdGlmaWNhdGlvbl9kYXRlLCBuYS5ybT1UKSwgDQogICAgICAgICAgICAgICAgICAgICAgbGhkXzIwMTBfbmFtZSwgTkEpKSAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHg9ZGF5c19zaW5jZV9maXJzdF9jYXNlICwgeT1hY2N1bXVsYXRlZF9jYXNlcywgY29sPWxoZF8yMDEwX25hbWUpKSArIA0KICAjIGdlb21fcG9pbnQoKSArIA0KICBnZW9tX2xpbmUoKSArIA0KICBnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsPWxhYiksIHNpemU9NCwgaGp1c3Q9LS4xLCBtaW4uc2VnbWVudC5sZW5ndGggPSAxMCkgKyANCiAgIyBmYWNldF93cmFwKH5saGRfMjAxMF9uYW1lKSArIA0KICBsYWJzKHN1YnRpdGxlID0gIkFjY3VtdWxhdGVkIGNvbmZpcm1lZCBDb3ZpZC0xOSBjYXNlcyAoU1lEKSwgYnkgcmVnaW9uIikgKyANCiAgeGxpbShjKDAsNTUwKSkgKw0KICBnZ2wobHAgPSAibm9uZSIpIA0KYGBgDQoNCmBgYHtyLCBmaWcud2lkdGg9OSwgZmlnLmhlaWdodD02fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgbXV0YXRlKGxoZF8yMDEwX25hbWUgPSBpZmVsc2UobGhkXzIwMTBfbmFtZSA9PSAiU3lkbmV5IiwgIk1ldHJvIFN5ZG5leSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaGRfMjAxMF9uYW1lKSkgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICAjIGZpbHRlcihsaGRfMjAxMF9uYW1lICVpbiUgYygiU291dGggRWFzdGVybiBTeWRuZXkiLCANCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vcnRoZXJuIFN5ZG5leSIsIA0KICAjICAgICAgICAgICAgICAgICAgICAgICAgICAiV2VzdGVybiBTeWRuZXkiLCANCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgIlNvdXRoIFdlc3Rlcm4gU3lkbmV5IiwgDQogICMgICAgICAgICAgICAgICAgICAgICAgICAgICJTeWRuZXkiKSB8IGlzLm5hKGxoZF8yMDEwX25hbWUpKSAlPiUgDQogIGNvdW50KGxoZF8yMDEwX25hbWUsIHBvc3Rjb2RlLCBub3RpZmljYXRpb25fZGF0ZSkgJT4lIA0KICBncm91cF9ieShsaGRfMjAxMF9uYW1lLCBwb3N0Y29kZSkgJT4lIA0KICBtdXRhdGUoZGF5c19zaW5jZV9maXJzdF9jYXNlID0gbm90aWZpY2F0aW9uX2RhdGUgLSBtaW4obm90aWZpY2F0aW9uX2RhdGUpKSAlPiUgDQogIG11dGF0ZShhY2N1bXVsYXRlZF9jYXNlcyA9IGN1bXN1bShuKSkgJT4lIA0KICBtdXRhdGUobGFiPWlmZWxzZShub3RpZmljYXRpb25fZGF0ZSA9PSBtYXgobm90aWZpY2F0aW9uX2RhdGUpLCBwb3N0Y29kZSwgTkEpKSAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHg9ZGF5c19zaW5jZV9maXJzdF9jYXNlICwgeT1hY2N1bXVsYXRlZF9jYXNlcywgDQogICAgICAgICAgICAgZ3JvdXA9cG9zdGNvZGUsDQogICAgICAgICAgICAgY29sPWxoZF8yMDEwX25hbWUpKSArIA0KICAjIGdlb21fcG9pbnQoKSArIA0KICBnZW9tX2xpbmUoKSArIA0KICBnZW9tX3RleHQoYWVzKGxhYmVsPWxhYiksIHNpemU9MywgaGp1c3Q9Im91dHdhcmQiKSArIA0KICBmYWNldF93cmFwKH5saGRfMjAxMF9uYW1lKSArDQogIGxhYnMoc3VidGl0bGUgPSAiQWNjdW11bGF0ZWQgY29uZmlybWVkIENvdmlkLTE5IGNhc2VzIChTeWRuZXkpLCBieSBwb3N0Y29kZSIpICsgDQogIHhsaW0oYygwLDU1MCkpICsNCiAgZ2dsKGxwID0gIm5vbmUiLCApDQpgYGANCg0KIyBNYXANCg0KTG9va3MgbGlrZSBlYWNoIHBvc3Rjb2RlIChQT0EpIGNhbiBvbmx5IGJlbG9uZyB0byBvbmUgTEdBLCB3aGljaCBpcyBub3QgdGhlIGNhc2UgZm9yIFNBMg0KDQpgYGB7cn0NCmNvbmZpcm1lZF9jYXNlcyAlPiUgDQogIGRpc3RpbmN0KHBvc3Rjb2RlLCBsZ2FfbmFtZTE5KSAlPiUgDQogIGNvdW50KHBvc3Rjb2RlKSAlPiUgDQogIHN1bW1hcmlzZShtYXgobikpICU+JSANCiAgcHVsbCgpDQpgYGANCg0KDQojIyBMR0ENCg0KYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD03fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGxnYV9uYW1lMTkgJWluJSBTWURfTEdBJExHQV9OQU1FMTkpICU+JSANCiAgY291bnQobGdhX25hbWUxOSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogIHJlbmFtZShMR0FfTkFNRTE5ID0gbGdhX25hbWUxOSkgJT4lIA0KICBtdXRhdGUoTEdBX05BTUUxOSA9IGZjdF9yZW9yZGVyKExHQV9OQU1FMTksIFRvdGFsX2Nhc2VzKSkgJT4lIA0KICBwbG90X21hcF9UTChTWURfTEdBLCAiTEdBX05BTUUxOSIsICJUb3RhbF9jYXNlcyIsIA0KICAgICAgICAgICAiVG90YWwgQ292aWQtMTkgY2FzZXMgYnkgTEdBIChTWUQgTWV0cm8pIiwgc2hvd19jb3VudCA9IFQpDQpgYGANCg0KIyMgUE9BDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTd9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBjb3VudChwb3N0Y29kZSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogIHJlbmFtZShQT0FfTkFNRTE2ID0gcG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKFBPQV9OQU1FMTYgPSBmY3RfcmVvcmRlcihhcy5mYWN0b3IoUE9BX05BTUUxNiksIFRvdGFsX2Nhc2VzKSkgJT4lIA0KICBwbG90X21hcF9UTChTWURfUE9BLCAiUE9BX05BTUUxNiIsICJUb3RhbF9jYXNlcyIsIA0KICAgICAgICAgICAiVG90YWwgQ292aWQtMTkgY2FzZXMgYnkgUE9BIChTWUQgTWV0cm8pIiwgDQogICAgICAgICAgIHNob3dfY291bnQgPSBULCBsYWJlbF9zaXplID0gMikNCmBgYA0KDQpgYGB7ciwgZmlnLndpZHRoPTkuNSwgZmlnLmhlaWdodD03fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKCEocG9zdGNvZGUgJWluJSBjKDIwMjYsIDIxNDUsIDIxNzApKSkgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBjb3VudChwb3N0Y29kZSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogIHJlbmFtZShQT0FfTkFNRTE2ID0gcG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKFBPQV9OQU1FMTYgPSBmY3RfcmVvcmRlcihhcy5mYWN0b3IoUE9BX05BTUUxNiksIFRvdGFsX2Nhc2VzKSkgJT4lIA0KICBwbG90X21hcF9UTChTWURfUE9BLCAiUE9BX05BTUUxNiIsICJUb3RhbF9jYXNlcyIsIA0KICAgICAgICAgICAiVG90YWwgQ292aWQtMTkgY2FzZXMgYnkgUE9BIChTWUQgTWV0cm8pLCBleGNsdWRpbmcgdG9wIDMgUE9BIiwgDQogICAgICAgICAgIHNob3dfY291bnQgPSBULCBsYWJlbF9zaXplID0gMikNCmBgYA0KDQojIyBOb3RlDQoNCk5vcnRoZXJuIEJlYWNoZXMgaGFzIG1hbnkgcG9zdGNvZGVzIHdoaWNoIHJlc3VsdCBpbiBtb3JlIGRpbHV0ZWQgY2hvcm9wbGV0aCBieSBQT0EuDQoNCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZGlzdGluY3QobGdhX25hbWUxOSwgcG9zdGNvZGUpICU+JSANCiAgY291bnQobGdhX25hbWUxOSwgbmFtZT0iTnVtYmVyX29mX3Bvc3Rjb2RlcyIpICU+JSANCiAgbGVmdF9qb2luKGNvbmZpcm1lZF9jYXNlcyAlPiUgY291bnQobGdhX25hbWUxOSwgbmFtZT0iVG90YWxfY2FzZXMiKSwgDQogICAgICAgICAgICBieT0ibGdhX25hbWUxOSIpICU+JSANCiAgc2xpY2VfbWF4KG49MzAsIG9yZGVyX2J5ID0gVG90YWxfY2FzZXMpICU+JSANCiAgZ2F0aGVyKGtleSwgdmFsdWUsIC1sZ2FfbmFtZTE5KSAlPiUgDQogIGdncGxvdChhZXMoeD1yZW9yZGVyKGxnYV9uYW1lMTksIHZhbHVlKSwgeT12YWx1ZSkpICsgDQogIGdlb21fY29sKCkgKyANCiAgZmFjZXRfd3JhcCh+a2V5LCBzY2FsZXMgPSAiZnJlZV94IikgKyANCiAgY29vcmRfZmxpcCgpICsgDQogIHhsYWIoIiIpICsgeWxhYigiIikgKyANCiAgZ2dsKCkNCmBgYA0KDQojIE1hcCBvdmVydGltZSBjdW11bGF0aXZlDQojIyBCeSBxdWFydGVyIHsudGFic2V0fQ0KIyMjIEFjY3VtdWxhdGVkIGNhc2VzDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTd9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBtdXRhdGUoeWVhcl9xdWFydGVyID0gcGFzdGUoeWVhcihub3RpZmljYXRpb25fZGF0ZSksICJRIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcXVhcnRlcihub3RpZmljYXRpb25fZGF0ZSksIHNlcD0iLSIpKSAlPiUgDQogIGNvdW50KHllYXJfcXVhcnRlciwgcG9zdGNvZGUsIG5hbWU9IlRvdGFsX2Nhc2VzIikgJT4lIA0KICBjb21wbGV0ZSh5ZWFyX3F1YXJ0ZXIsIHBvc3Rjb2RlLCBmaWxsID0gbGlzdChUb3RhbF9jYXNlcz0wKSkgJT4lIA0KICBncm91cF9ieShwb3N0Y29kZSkgJT4lIA0KICBtdXRhdGUoQWNjdW11bGF0ZWRfY2FzZXMgPSBjdW1zdW0oVG90YWxfY2FzZXMpKSAlPiUgDQogIGdyb3VwX2J5KHllYXJfcXVhcnRlcikgJT4lIA0KICBtdXRhdGUoQWNjdW11bGF0ZWRfc2hhcmUgPSAoQWNjdW11bGF0ZWRfY2FzZXMvc3VtKEFjY3VtdWxhdGVkX2Nhc2VzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybT1UKSkpICU+JSANCiAgbXV0YXRlKGZhY2V0X3ZhciA9IHBhc3RlMCh5ZWFyX3F1YXJ0ZXIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJcbkFjY3VtdWxhdGVkOiAiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21tYShzdW0oQWNjdW11bGF0ZWRfY2FzZXMpKSkpICU+JSANCiAgcmVuYW1lKFBPQV9OQU1FMTYgPSBwb3N0Y29kZSkgJT4lIA0KICANCiAgcGxvdF9tYXBfVEwocm1hcHNoYXBlcjo6bXNfc2ltcGxpZnkoDQogICAgU1lEX1BPQVtTWURfUE9BJFBPQV9OQU1FMTYgJWluJSBhcy5jaGFyYWN0ZXIoDQogICAgICBjb25maXJtZWRfY2FzZXMkcG9zdGNvZGUpICxdLCAuMDEpLCANCiAgICAgICAgICAgICAgIlBPQV9OQU1FMTYiLCAiQWNjdW11bGF0ZWRfY2FzZXMiLCANCiAgICAgICAgICAgIlRvdGFsIENvdmlkLTE5IGNhc2VzIGJ5IFBPQSAoU1lEIE1ldHJvKSIsIA0KICAgICAgICAgICByZXR1cm5fb2JqPSJtYXAiKSArIA0KICBmYWNldF93cmFwKH5mYWNldF92YXIpICsgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQ0KYGBgDQoNCiMjIyBBY2N1bXVsYXRlZCBzaGFyZQ0KDQpgYGB7ciwgZmlnLndpZHRoPTkuNSwgZmlnLmhlaWdodD03fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgbXV0YXRlKHllYXJfcXVhcnRlciA9IHBhc3RlKHllYXIobm90aWZpY2F0aW9uX2RhdGUpLCAiUSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHF1YXJ0ZXIobm90aWZpY2F0aW9uX2RhdGUpLCBzZXA9Ii0iKSkgJT4lIA0KICBjb3VudCh5ZWFyX3F1YXJ0ZXIsIHBvc3Rjb2RlLCBuYW1lPSJUb3RhbF9jYXNlcyIpICU+JSANCiAgY29tcGxldGUoeWVhcl9xdWFydGVyLCBwb3N0Y29kZSwgZmlsbCA9IGxpc3QoVG90YWxfY2FzZXM9MCkpICU+JSANCiAgZ3JvdXBfYnkocG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX2Nhc2VzID0gY3Vtc3VtKFRvdGFsX2Nhc2VzKSkgJT4lIA0KICBncm91cF9ieSh5ZWFyX3F1YXJ0ZXIpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX3NoYXJlID0gKEFjY3VtdWxhdGVkX2Nhc2VzL3N1bShBY2N1bXVsYXRlZF9jYXNlcywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm09VCkpKSAlPiUNCiAgbXV0YXRlKGZhY2V0X3ZhciA9IHBhc3RlMCh5ZWFyX3F1YXJ0ZXIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJcbkFjY3VtdWxhdGVkOiAiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21tYShzdW0oQWNjdW11bGF0ZWRfY2FzZXMpKSkpICU+JSANCiAgcmVuYW1lKFBPQV9OQU1FMTYgPSBwb3N0Y29kZSkgJT4lIA0KICANCiAgcGxvdF9tYXBfVEwocm1hcHNoYXBlcjo6bXNfc2ltcGxpZnkoDQogICAgU1lEX1BPQVtTWURfUE9BJFBPQV9OQU1FMTYgJWluJSBhcy5jaGFyYWN0ZXIoDQogICAgICBjb25maXJtZWRfY2FzZXMkcG9zdGNvZGUpICxdLCAuMDEpLCANCiAgICAgICAgICAgICAgIlBPQV9OQU1FMTYiLCAiQWNjdW11bGF0ZWRfc2hhcmUiLCANCiAgICAgICAgICAgIlRvdGFsIENvdmlkLTE5IGNhc2VzIGJ5IFBPQSAoU1lEIE1ldHJvKSIsIA0KICAgICAgICAgICByZXR1cm5fb2JqPSJtYXAiKSArIA0KICBmYWNldF93cmFwKH5mYWNldF92YXIpICsgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQ0KYGBgDQoNCiMjIEJ5IHdlZWsgTWFyLU1heSAyMDIwIHsudGFic2V0fQ0KIyMjIEFjY3VtdWxhdGVkIGNhc2VzDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTEwfQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgZmlsdGVyKHllYXIobm90aWZpY2F0aW9uX2RhdGUpID09IDIwMjAsIA0KICAgICAgICAgIyBtb250aChub3RpZmljYXRpb25fZGF0ZSkgJWluJSAzOjUsIA0KICAgICAgICAgaXNvd2Vlayhub3RpZmljYXRpb25fZGF0ZSkgJWluJSAxMDoyMykgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBtdXRhdGUoaXNvd2VlayA9IGlzb3dlZWsobm90aWZpY2F0aW9uX2RhdGUpKSAlPiUgDQogIGNvdW50KGlzb3dlZWssIHBvc3Rjb2RlLCBuYW1lPSJUb3RhbF9jYXNlcyIpICU+JSANCiAgY29tcGxldGUoaXNvd2VlaywgcG9zdGNvZGUsIGZpbGwgPSBsaXN0KFRvdGFsX2Nhc2VzPTApKSAlPiUgDQogIGdyb3VwX2J5KHBvc3Rjb2RlKSAlPiUgDQogIG11dGF0ZShBY2N1bXVsYXRlZF9jYXNlcyA9IGN1bXN1bShUb3RhbF9jYXNlcykpICU+JSANCiAgZ3JvdXBfYnkoaXNvd2VlaykgJT4lIA0KICBtdXRhdGUoQWNjdW11bGF0ZWRfc2hhcmUgPSAoQWNjdW11bGF0ZWRfY2FzZXMvc3VtKEFjY3VtdWxhdGVkX2Nhc2VzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybT1UKSkpICU+JQ0KICBtdXRhdGUoZmFjZXRfdmFyID0gcGFzdGUwKCJ3ZWVrICIsIGlzb3dlZWssIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJcbkFjY3VtdWxhdGVkOiAiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21tYShzdW0oQWNjdW11bGF0ZWRfY2FzZXMpKSkpICU+JSANCiAgcmVuYW1lKFBPQV9OQU1FMTYgPSBwb3N0Y29kZSkgJT4lIA0KICBtdXRhdGUoUE9BX05BTUUxNiA9IGZjdF9yZW9yZGVyKGFzLmZhY3RvcihQT0FfTkFNRTE2KSwgVG90YWxfY2FzZXMpKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgDQogIGZpbHRlcighaXMubmEoaXNvd2VlaykpICU+JSANCiAgDQogIHBsb3RfbWFwX1RMKHJtYXBzaGFwZXI6Om1zX3NpbXBsaWZ5KFNZRF9QT0EsIC4wMSksIA0KICAgICAgICAgICAgICAiUE9BX05BTUUxNiIsICJBY2N1bXVsYXRlZF9jYXNlcyIsIA0KICAgICAgICAgICAgICAiVG90YWwgQ292aWQtMTkgY2FzZXMgYnkgUE9BIChTWUQgTWV0cm8pIiwgDQogICAgICAgICAgICAgIHJldHVybl9vYmo9Im1hcCIpICsgDQogIGZhY2V0X3dyYXAofmZhY2V0X3ZhcikNCmBgYA0KDQojIyMgQWNjdW11bGF0ZWQgc2hhcmUNCg0KYGBge3IsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9MTB9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBmaWx0ZXIoeWVhcihub3RpZmljYXRpb25fZGF0ZSkgPT0gMjAyMCwgDQogICAgICAgICAjIG1vbnRoKG5vdGlmaWNhdGlvbl9kYXRlKSAlaW4lIDM6NSwgDQogICAgICAgICBpc293ZWVrKG5vdGlmaWNhdGlvbl9kYXRlKSAlaW4lIDEwOjIzKSAlPiUgDQogIGZpbHRlcihhcy5jaGFyYWN0ZXIocG9zdGNvZGUpICVpbiUgU1lEX1BPQSRQT0FfTkFNRTE2KSAlPiUgDQogIG11dGF0ZShpc293ZWVrID0gaXNvd2Vlayhub3RpZmljYXRpb25fZGF0ZSkpICU+JSANCiAgY291bnQoaXNvd2VlaywgcG9zdGNvZGUsIG5hbWU9IlRvdGFsX2Nhc2VzIikgJT4lIA0KICBjb21wbGV0ZShpc293ZWVrLCBwb3N0Y29kZSwgZmlsbCA9IGxpc3QoVG90YWxfY2FzZXM9MCkpICU+JSANCiAgZ3JvdXBfYnkocG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX2Nhc2VzID0gY3Vtc3VtKFRvdGFsX2Nhc2VzKSkgJT4lIA0KICBncm91cF9ieShpc293ZWVrKSAlPiUgDQogIG11dGF0ZShBY2N1bXVsYXRlZF9zaGFyZSA9IChBY2N1bXVsYXRlZF9jYXNlcy9zdW0oQWNjdW11bGF0ZWRfY2FzZXMsIG5hLnJtPVQpKSkgJT4lIA0KICByZW5hbWUoUE9BX05BTUUxNiA9IHBvc3Rjb2RlKSAlPiUgDQogIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoYXMuZmFjdG9yKFBPQV9OQU1FMTYpLCBUb3RhbF9jYXNlcykpICU+JSANCiAgbXV0YXRlKGZhY2V0X3ZhciA9IHBhc3RlMCgid2VlayAiLCBpc293ZWVrLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiXG5BY2N1bXVsYXRlZDogIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tbWEoc3VtKEFjY3VtdWxhdGVkX2Nhc2VzKSkpKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgDQogIGZpbHRlcighaXMubmEoaXNvd2VlaykpICU+JSANCiAgDQogIHBsb3RfbWFwX1RMKHJtYXBzaGFwZXI6Om1zX3NpbXBsaWZ5KFNZRF9QT0EsIC4wMSksIA0KICAgICAgICAgICAgICAiUE9BX05BTUUxNiIsICJBY2N1bXVsYXRlZF9zaGFyZSIsIA0KICAgICAgICAgICAgICAiVG90YWwgQ292aWQtMTkgY2FzZXMgYnkgUE9BIChTWUQgTWV0cm8pIiwgDQogICAgICAgICAgICAgIHJldHVybl9vYmo9Im1hcCIpICsgDQogIGZhY2V0X3dyYXAofmZhY2V0X3ZhcikNCmBgYA0KDQojIERpc3RyaWJ1dGlvbiBvZiBzaGFyZSBvdmVydGltZQ0KIyMgQnkgcXVhcnRlcg0KDQpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9My4zfQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgbXV0YXRlKHllYXJfcXVhcnRlciA9IHBhc3RlKHllYXIobm90aWZpY2F0aW9uX2RhdGUpLCAiUSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHF1YXJ0ZXIobm90aWZpY2F0aW9uX2RhdGUpLCBzZXA9Ii0iKSkgJT4lIA0KICBjb3VudCh5ZWFyX3F1YXJ0ZXIsIHBvc3Rjb2RlLCBuYW1lPSJUb3RhbF9jYXNlcyIpICU+JSANCiAgY29tcGxldGUoeWVhcl9xdWFydGVyLCBwb3N0Y29kZSwgZmlsbCA9IGxpc3QoVG90YWxfY2FzZXM9MCkpICU+JSANCiAgZ3JvdXBfYnkocG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX2Nhc2VzID0gY3Vtc3VtKFRvdGFsX2Nhc2VzKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBjb21wbGV0ZSh5ZWFyX3F1YXJ0ZXIsIHBvc3Rjb2RlKSAlPiUgDQogIHJlcGxhY2VfbmEobGlzdChBY2N1bXVsYXRlZF9jYXNlcz0wKSkgJT4lIA0KICBncm91cF9ieSh5ZWFyX3F1YXJ0ZXIpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX3NoYXJlID0gKEFjY3VtdWxhdGVkX2Nhc2VzL3N1bShBY2N1bXVsYXRlZF9jYXNlcywgbmEucm09VCkpKSAlPiUgDQogIHJlbmFtZShQT0FfTkFNRTE2ID0gcG9zdGNvZGUpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgDQogIGdncGxvdChhZXMoeD15ZWFyX3F1YXJ0ZXIsIHk9QWNjdW11bGF0ZWRfY2FzZXMsIA0KICAgICAgICAgICAgIGZpbGw9QWNjdW11bGF0ZWRfY2FzZXMgPiA1MCwNCiAgICAgICAgICAgICBncm91cD1hcy5mYWN0b3IoUE9BX05BTUUxNikpKSArIA0KICBnZW9tX2NvbChjb2w9IndoaXRlIiwgc2l6ZT0uMSkgKyANCiAgZ2dmKGZjID0gRENbMjoxXSkgKyANCiAgZ2dsKCJ0b3AiLCBsdCA9IFQpDQpgYGANCg0KDQpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Mi41fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgbXV0YXRlKHllYXJfcXVhcnRlciA9IHBhc3RlKHllYXIobm90aWZpY2F0aW9uX2RhdGUpLCAiUSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHF1YXJ0ZXIobm90aWZpY2F0aW9uX2RhdGUpLCBzZXA9Ii0iKSkgJT4lIA0KICBjb3VudCh5ZWFyX3F1YXJ0ZXIsIHBvc3Rjb2RlLCBuYW1lPSJUb3RhbF9jYXNlcyIpICU+JSANCiAgZ3JvdXBfYnkocG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX2Nhc2VzID0gY3Vtc3VtKFRvdGFsX2Nhc2VzKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBjb21wbGV0ZSh5ZWFyX3F1YXJ0ZXIsIHBvc3Rjb2RlKSAlPiUgDQogIHJlcGxhY2VfbmEobGlzdChBY2N1bXVsYXRlZF9jYXNlcz0wKSkgJT4lIA0KICBncm91cF9ieSh5ZWFyX3F1YXJ0ZXIpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX3NoYXJlID0gKEFjY3VtdWxhdGVkX2Nhc2VzL3N1bShBY2N1bXVsYXRlZF9jYXNlcywgbmEucm09VCkpKSAlPiUgDQogIHJlbmFtZShQT0FfTkFNRTE2ID0gcG9zdGNvZGUpICU+JSANCiAgDQogIGdncGxvdChhZXMoeD1BY2N1bXVsYXRlZF9zaGFyZSwgZmlsbD1hcy5mYWN0b3IoeWVhcl9xdWFydGVyKSkpICsgDQogICMgZ2VvbV9kZW5zaXR5KCkgKyANCiAgZ2VvbV9oaXN0b2dyYW0oKSArIA0KICBmYWNldF93cmFwKH55ZWFyX3F1YXJ0ZXIsIG5yb3cgPSAxKSArIA0KICB4bGltKDAsLjAzKSArIA0KICB5bGltKDAsNDApICsNCiAgZ2dsKCJub25lIikNCmBgYA0KDQojIyBCeSB3ZWVrDQoNCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD0zLjN9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBmaWx0ZXIoeWVhcihub3RpZmljYXRpb25fZGF0ZSkgPT0gMjAyMCwgDQogICAgICAgICAjIG1vbnRoKG5vdGlmaWNhdGlvbl9kYXRlKSAlaW4lIDM6NSwgDQogICAgICAgICBpc293ZWVrKG5vdGlmaWNhdGlvbl9kYXRlKSAlaW4lIDEwOjIzKSAlPiUgDQogIGZpbHRlcihhcy5jaGFyYWN0ZXIocG9zdGNvZGUpICVpbiUgU1lEX1BPQSRQT0FfTkFNRTE2KSAlPiUgDQogIG11dGF0ZShpc293ZWVrID0gaXNvd2Vlayhub3RpZmljYXRpb25fZGF0ZSkpICU+JSANCiAgY291bnQoaXNvd2VlaywgcG9zdGNvZGUsIG5hbWU9IlRvdGFsX2Nhc2VzIikgJT4lIA0KICBjb21wbGV0ZShpc293ZWVrLCBwb3N0Y29kZSwgZmlsbCA9IGxpc3QoVG90YWxfY2FzZXM9MCkpICU+JSANCiAgZ3JvdXBfYnkocG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX2Nhc2VzID0gY3Vtc3VtKFRvdGFsX2Nhc2VzKSkgJT4lIA0KICBncm91cF9ieShpc293ZWVrKSAlPiUgDQogIG11dGF0ZShBY2N1bXVsYXRlZF9zaGFyZSA9IChBY2N1bXVsYXRlZF9jYXNlcy9zdW0oQWNjdW11bGF0ZWRfY2FzZXMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtPVQpKSkgJT4lDQogIG11dGF0ZShmYWNldF92YXIgPSBwYXN0ZTAoIndlZWsgIiwgaXNvd2VlaywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIlxuQWNjdW11bGF0ZWQ6ICIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbW1hKHN1bShBY2N1bXVsYXRlZF9jYXNlcykpKSkgJT4lIA0KICByZW5hbWUoUE9BX05BTUUxNiA9IHBvc3Rjb2RlKSAlPiUgDQogIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoYXMuZmFjdG9yKFBPQV9OQU1FMTYpLCBUb3RhbF9jYXNlcykpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgZmlsdGVyKCFpcy5uYShpc293ZWVrKSkgJT4lIA0KICANCiAgZ2dwbG90KGFlcyh4PWlzb3dlZWssIHk9QWNjdW11bGF0ZWRfY2FzZXMsIA0KICAgICAgICAgICAgIGZpbGw9QWNjdW11bGF0ZWRfY2FzZXMgPiAyMCwNCiAgICAgICAgICAgICBncm91cD1hcy5mYWN0b3IoUE9BX05BTUUxNikpKSArIA0KICBnZW9tX2NvbChjb2w9IndoaXRlIiwgc2l6ZT0uMSkgKyANCiAgZ2d4KHJvdW5kLCBwYm49MTIpICsNCiAgZ2dmKGZjID0gRENbMjoxXSkgKyANCiAgZ2dsKCJ0b3AiLCBsdCA9IFQpDQpgYGANCg0KDQpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9NX0NCmNvbmZpcm1lZF9jYXNlcyAlPiUgDQogIGZpbHRlcihhcy5jaGFyYWN0ZXIocG9zdGNvZGUpICVpbiUgU1lEX1BPQSRQT0FfTkFNRTE2KSAlPiUgDQogIGZpbHRlcih5ZWFyKG5vdGlmaWNhdGlvbl9kYXRlKSA9PSAyMDIwLCANCiAgICAgICAgICMgbW9udGgobm90aWZpY2F0aW9uX2RhdGUpICVpbiUgMzo1LCANCiAgICAgICAgIGlzb3dlZWsobm90aWZpY2F0aW9uX2RhdGUpICVpbiUgMTA6MjMpICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgbXV0YXRlKGlzb3dlZWsgPSBpc293ZWVrKG5vdGlmaWNhdGlvbl9kYXRlKSkgJT4lIA0KICBjb3VudChpc293ZWVrLCBwb3N0Y29kZSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogIGNvbXBsZXRlKGlzb3dlZWssIHBvc3Rjb2RlLCBmaWxsID0gbGlzdChUb3RhbF9jYXNlcz0wKSkgJT4lIA0KICBncm91cF9ieShwb3N0Y29kZSkgJT4lIA0KICBtdXRhdGUoQWNjdW11bGF0ZWRfY2FzZXMgPSBjdW1zdW0oVG90YWxfY2FzZXMpKSAlPiUgDQogIGdyb3VwX2J5KGlzb3dlZWspICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX3NoYXJlID0gKEFjY3VtdWxhdGVkX2Nhc2VzL3N1bShBY2N1bXVsYXRlZF9jYXNlcywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm09VCkpKSAlPiUNCiAgbXV0YXRlKGZhY2V0X3ZhciA9IHBhc3RlMCgid2VlayAiLCBpc293ZWVrLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiXG5BY2N1bXVsYXRlZDogIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tbWEoc3VtKEFjY3VtdWxhdGVkX2Nhc2VzKSkpKSAlPiUgDQogIHJlbmFtZShQT0FfTkFNRTE2ID0gcG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKFBPQV9OQU1FMTYgPSBmY3RfcmVvcmRlcihhcy5mYWN0b3IoUE9BX05BTUUxNiksIFRvdGFsX2Nhc2VzKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKGlzb3dlZWspKSAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHg9QWNjdW11bGF0ZWRfc2hhcmUsIGZpbGw9YXMuZmFjdG9yKGlzb3dlZWspKSkgKyANCiAgIyBnZW9tX2RlbnNpdHkoKSArIA0KICBnZW9tX2hpc3RvZ3JhbSgpICsgDQogIGZhY2V0X3dyYXAofmlzb3dlZWssIG5yb3cgPSAzLCBsYWJlbGxlciA9ICJsYWJlbF9ib3RoIikgKyANCiAgeGxpbSgwLC4wMykgKyANCiAgeWxpbSgwLDQwKSArDQogIGdnbCgibm9uZSIpDQpgYGANCg0KIyBMb2NhbCBQT0kNCiMjIFB1YmxpYyB0cmFuc3BvcnQNCg0KYGBge3IsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9N30NCmNvbmZpcm1lZF9jYXNlcyAlPiUgDQogICAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgICBjb3VudChwb3N0Y29kZSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogICAgcmVuYW1lKFBPQV9OQU1FMTYgPSBwb3N0Y29kZSkgJT4lIA0KICAgIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoYXMuZmFjdG9yKFBPQV9OQU1FMTYpLCBUb3RhbF9jYXNlcykpICU+JSANCiAgICBwbG90X21hcF9UTChTWURfUE9BLCAiUE9BX05BTUUxNiIsICJUb3RhbF9jYXNlcyIsIA0KICAgICAgICAgICAgICAgICJUb3RhbCBDb3ZpZC0xOSBjYXNlcyBieSBQT0EgKFNZRCBNZXRybyksIHdpdGggcHVibGljIHRyYW5zcG9ydCIsIA0KICAgICAgICAgICAgICAgIHNob3dfY291bnQgPSBULCBsYWJlbF9zaXplID0gMiwgcmV0dXJuX29iaiA9ICJtYXAiKSArDQogIA0KICAjIGdlb21fbWFwKGluaGVyaXQuYWVzID0gRkFMU0UsIGFscGhhPS44NSwNCiAgIyAgICAgICAgICBhZXMobWFwX2lkID0gaWQpLCBtYXAgPSB0aWR5KFNZRF9QT0EpLCANCiAgIyAgICAgICAgICBjb2w9ImdyZXk1MCIsIHNpemU9LjMsIGZpbGw9IndoaXRlIikgKw0KICBnZW9tX2xpbmUoZGF0YSA9IFNZRF90cmFpbnMsIA0KICAgICAgICAgICAgYWVzKHg9bG9uLCB5PWxhdCwgY29sPSJUcmFpbiIsDQogICAgICAgICAgICAgICAgZ3JvdXAgPSBgUmFpbHdheSBsaW5lKHMpYCksDQogICAgICAgICAgICBzaXplPS44KSArDQogIGdlb21fbGluZShkYXRhID0gU1lEX2ZlcnJpZXMsIA0KICAgICAgICAgICAgYWVzKHg9bG9uLCB5PWxhdCwgY29sPSJGZXJyeSIpLA0KICAgICAgICAgICAgIHNpemU9LjgpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBTWURfbGlnaHRyYWlscywgDQogICAgICAgICAgICBhZXMoeD1sb24sIHk9bGF0LCBjb2w9IkxpZ2h0cmFpbCIpLA0KICAgICAgICAgICAgIHNpemU9LjgpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBTWURfbWV0cm8sIA0KICAgICAgICAgICAgYWVzKHg9bG9uLCB5PWxhdCwgY29sPSJNZXRybyIpLA0KICAgICAgICAgICAgIHNpemU9LjgpICsNCiAgZ2djKGMoImRlZXBza3libHVlIiwgInJlZCIsICJkYXJrZ3JlZW4iLCAib3JhbmdlIikpICsgDQogIGd1aWRlcyhjb2w9Z3VpZGVfbGVnZW5kKHRpdGxlPSJUcmFuc3BvcnRfbW9kZSIpKSArIA0KICBleHBhbmRfbGltaXRzKHggPSB0aWR5KFNZRF9QT0EpJGxvbmcsIHkgPSB0aWR5KFNZRF9QT0EpJGxhdCkgKw0KICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMTUwLjcsIDE1MS40OCksIHlsaW0gPSBjKC0zNC4xLCAtMzMuNSkpICsNCiAgdGhlbWVfdm9pZCgpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gYyguOSwuMzUpKQ0KYGBgDQoNCg0KIyMgSG9zcGl0YWxzLCBTY2hvb2xzLCBTdXBlcm1hcmtldA0KDQpgYGB7ciwgZmlnLndpZHRoPTkuNSwgZmlnLmhlaWdodD04fQ0KYmluZF9yb3dzKA0KICBTWURfc2hvcHMgJT4lIHNlbGVjdChsb24sIGxhdCkgJT4lIA0KICAgIHJlbmFtZShMb25nID0gbG9uLCBMYXQgPSBsYXQpICU+JSBtdXRhdGUob2JqID0gIlNob3BwaW5nIGNlbnRyZXMiKSwgDQogIFNZRF9zdXBlcm1hcmtldHMgJT4lIHNlbGVjdChsb24sIGxhdCkgJT4lIA0KICAgIHJlbmFtZShMb25nID0gbG9uLCBMYXQgPSBsYXQpICU+JSBtdXRhdGUob2JqID0gIlN1cGVybWFya2V0cyIpLCANCiAgU1lEX2hvc3BpdGFscyAlPiUgc2VsZWN0KExvbmdpdHVkZSwgTGF0aXR1ZGUpICU+JSANCiAgICByZW5hbWUoTG9uZyA9IExvbmdpdHVkZSwgTGF0ID0gTGF0aXR1ZGUpICU+JSBtdXRhdGUob2JqID0gIkhvc3BpdGFscyIpLCANCiAgcmJpbmQoU1lEX3NzY2hvb2xzICU+JSBzZWxlY3QoTG9uZywgTGF0KSwNCiAgICAgICAgU1lEX3BzY2hvb2xzICU+JSBzZWxlY3QoTG9uZywgTGF0KSkgJT4lIG11dGF0ZShvYmogPSAiU2Nob29scyIpDQopICU+JSANCiAgZ2dwbG90KCkgKyAgDQogIGdlb21fbWFwKGRhdGEgPSBTWURfUE9BLCBpbmhlcml0LmFlcyA9IEZBTFNFLCBhbHBoYT0uODUsDQogICAgICAgICAgIGFlcyhtYXBfaWQgPSBpZCksIG1hcCA9IHRpZHkoU1lEX1BPQSksIA0KICAgICAgICAgICBjb2w9ImdyZXk1MCIsIHNpemU9LjIsIGZpbGw9IndoaXRlIikgKw0KICBnZW9tX2ppdHRlcihhZXMoeD1Mb25nLCB5PUxhdCwgY29sPW9iaiksIHNpemU9LjgsIGFscGhhPS41KSArIA0KICBzdGF0X2RlbnNpdHkyZChhZXMoeD1Mb25nLCB5PUxhdCwgDQogICAgICAgICAgICAgICAgICAgICBmaWxsPS4ubGV2ZWwuLiwgYWxwaGE9Li5sZXZlbC4uLCBjb2w9b2JqKSwNCiAgICAgICAgICAgICAgICAgYmlud2lkdGggPSAxLjIsIGdlb209InBvbHlnb24iLCBzaXplPS4yMykgKyANCiAgZmFjZXRfd3JhcCh+b2JqKSArDQogIGV4cGFuZF9saW1pdHMoeCA9IHRpZHkoU1lEX1BPQSkkbG9uZywgeSA9IHRpZHkoU1lEX1BPQSkkbGF0KSArDQogIHhsaW0oMTUwLjcsMTUxLjQ4KSArIHlsaW0oLTM0LjEsLTMzLjUpICsNCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9IndoaXRlIiwgaGlnaD1EQ1s3XSkgKyANCiAgc2NhbGVfYWxwaGFfY29udGludW91cyhyYW5nZSA9IGMoMCwuMykpICsgDQogIGdnYyhmYyA9IGMoImRhcmtyZWQiLCAiZGVlcHNreWJsdWUiLCAiYmxhY2siLCAiZGFya2dyZWVuIikpICsgDQogIHRoZW1lX3ZvaWQoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgDQogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgDQogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNSkpDQpgYGANCg0KYGBge3IsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9N30NCmNvbmZpcm1lZF9jYXNlcyAlPiUgDQogIGZpbHRlcihhcy5jaGFyYWN0ZXIocG9zdGNvZGUpICVpbiUgU1lEX1BPQSRQT0FfTkFNRTE2KSAlPiUgDQogIGNvdW50KHBvc3Rjb2RlLCBuYW1lPSJUb3RhbF9jYXNlcyIpICU+JSANCiAgcmVuYW1lKFBPQV9OQU1FMTYgPSBwb3N0Y29kZSkgJT4lIA0KICBtdXRhdGUoUE9BX05BTUUxNiA9IGZjdF9yZW9yZGVyKGFzLmZhY3RvcihQT0FfTkFNRTE2KSwgVG90YWxfY2FzZXMpKSAlPiUgDQogIHBsb3RfbWFwX1RMKFNZRF9QT0EsICJQT0FfTkFNRTE2IiwgIlRvdGFsX2Nhc2VzIiwgDQogICAgICAgICAgICAgICJUb3RhbCBDb3ZpZC0xOSBjYXNlcyBieSBQT0EgKFNZRCBNZXRybyksIHdpdGggaG9zcGl0YWxzLCBzY2hvb2xzICYgc3VwZXJtYXJrZXRzIiwgDQogICAgICAgICAgICAgIHNob3dfY291bnQgPSBULCBsYWJlbF9zaXplID0gMiwgcmV0dXJuX29iaiA9ICJtYXAiKSArDQogIA0KICAjIGdlb21fbWFwKGRhdGEgPSBTWURfUE9BLCBpbmhlcml0LmFlcyA9IEZBTFNFLCBhbHBoYT0uODUsDQogICMgICAgICAgICAgYWVzKG1hcF9pZCA9IGlkKSwgbWFwID0gdGlkeShTWURfUE9BKSwgDQogICMgICAgICAgICAgY29sPSJncmV5NTAiLCBzaXplPS4zLCBmaWxsPSJ3aGl0ZSIpICsNCiAgZ2VvbV9qaXR0ZXIoZGF0YSA9IGJpbmRfcm93cygNCiAgICBTWURfc2hvcHMgJT4lIHNlbGVjdChsb24sIGxhdCkgJT4lIA0KICAgICAgcmVuYW1lKExvbmcgPSBsb24sIExhdCA9IGxhdCkgJT4lIG11dGF0ZShvYmogPSAiU2hvcHBpbmcgY2VudHJlcyIpLCANCiAgICBTWURfc3VwZXJtYXJrZXRzICU+JSBzZWxlY3QobG9uLCBsYXQpICU+JSANCiAgICAgIHJlbmFtZShMb25nID0gbG9uLCBMYXQgPSBsYXQpICU+JSBtdXRhdGUob2JqID0gIlN1cGVybWFya2V0cyIpLCANCiAgICBTWURfaG9zcGl0YWxzICU+JSBzZWxlY3QoTG9uZ2l0dWRlLCBMYXRpdHVkZSkgJT4lIA0KICAgICAgcmVuYW1lKExvbmcgPSBMb25naXR1ZGUsIExhdCA9IExhdGl0dWRlKSAlPiUgbXV0YXRlKG9iaiA9ICJIb3NwaXRhbHMiKSwgDQogICAgcmJpbmQoU1lEX3NzY2hvb2xzICU+JSBzZWxlY3QoTG9uZywgTGF0KSwNCiAgICAgICAgICBTWURfcHNjaG9vbHMgJT4lIHNlbGVjdChMb25nLCBMYXQpKSAlPiUgbXV0YXRlKG9iaiA9ICJTY2hvb2xzIikNCiAgKSwgDQogIHNpemUgPSAxLCBhbHBoYSA9IC4zLCBhZXMoeD1Mb25nLCB5PUxhdCxjb2w9b2JqKSkgKw0KICBleHBhbmRfbGltaXRzKHggPSB0aWR5KFNZRF9QT0EpJGxvbmcsIHkgPSB0aWR5KFNZRF9QT0EpJGxhdCkgKw0KICB4bGltKDE1MC43LDE1MS40OCkgKyB5bGltKC0zNC4xLC0zMy41KSArDQogICMgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9IndoaXRlIiwgaGlnaD1EQ1s3XSkgKyANCiAgc2NhbGVfYWxwaGFfY29udGludW91cyhyYW5nZSA9IGMoMCwuMykpICsgDQogIGdnYyhmYyA9IGMoImRhcmtyZWQiLCAiZGFya2JsdWUiLCAiZGFya29yYW5nZSIsICJkYXJrZ3JlZW4iKSkgKyANCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT0zKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZT0iUE9JIikpICsgDQogIHRoZW1lX3ZvaWQoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoLjksLjI1KSwgDQogICAgICAgICMgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCANCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE1KSkNCmBgYA0KIyMgUE9JIGNvbWJpbmVkDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTd9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBjb3VudChwb3N0Y29kZSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogIHJlbmFtZShQT0FfTkFNRTE2ID0gcG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKFBPQV9OQU1FMTYgPSBmY3RfcmVvcmRlcihhcy5mYWN0b3IoUE9BX05BTUUxNiksIFRvdGFsX2Nhc2VzKSkgJT4lIA0KICBwbG90X21hcF9UTChTWURfUE9BLCAiUE9BX05BTUUxNiIsICJUb3RhbF9jYXNlcyIsIA0KICAgICAgICAgICAgICAiVG90YWwgQ292aWQtMTkgY2FzZXMgYnkgUE9BIChTWUQgTWV0cm8pLCB3aXRoIGhvc3BpdGFscywgc2Nob29scyAmIHN1cGVybWFya2V0cyIsIA0KICAgICAgICAgICAgICBzaG93X2NvdW50ID0gVCwgbGFiZWxfc2l6ZSA9IDIsIHJldHVybl9vYmogPSAibWFwIikgKw0KICBnZW9tX2xpbmUoZGF0YSA9IFNZRF90cmFpbnMsIA0KICAgICAgICAgICAgYWVzKHg9bG9uLCB5PWxhdCwgY29sPSJUcmFpbiIsDQogICAgICAgICAgICAgICAgZ3JvdXAgPSBgUmFpbHdheSBsaW5lKHMpYCksDQogICAgICAgICAgICBzaXplPS44KSArDQogIGdlb21fbGluZShkYXRhID0gU1lEX2ZlcnJpZXMsIA0KICAgICAgICAgICAgYWVzKHg9bG9uLCB5PWxhdCwgY29sPSJGZXJyeSIpLA0KICAgICAgICAgICAgIHNpemU9LjgpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBTWURfbGlnaHRyYWlscywgDQogICAgICAgICAgICBhZXMoeD1sb24sIHk9bGF0LCBjb2w9IkxpZ2h0cmFpbCIpLA0KICAgICAgICAgICAgIHNpemU9LjgpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBTWURfbWV0cm8sIA0KICAgICAgICAgICAgYWVzKHg9bG9uLCB5PWxhdCwgY29sPSJNZXRybyIpLA0KICAgICAgICAgICAgIHNpemU9LjgpICsNCiAgDQogICMgZ2VvbV9tYXAoZGF0YSA9IFNZRF9QT0EsIGluaGVyaXQuYWVzID0gRkFMU0UsIGFscGhhPS44NSwNCiAgIyAgICAgICAgICBhZXMobWFwX2lkID0gaWQpLCBtYXAgPSB0aWR5KFNZRF9QT0EpLCANCiAgIyAgICAgICAgICBjb2w9ImdyZXk1MCIsIHNpemU9LjMsIGZpbGw9IndoaXRlIikgKw0KICBnZW9tX2ppdHRlcihkYXRhID0gYmluZF9yb3dzKA0KICAgIFNZRF9zaG9wcyAlPiUgc2VsZWN0KGxvbiwgbGF0KSAlPiUgDQogICAgICByZW5hbWUoTG9uZyA9IGxvbiwgTGF0ID0gbGF0KSAlPiUgbXV0YXRlKG9iaiA9ICJTaG9wcGluZyBjZW50cmVzIiksIA0KICAgIFNZRF9zdXBlcm1hcmtldHMgJT4lIHNlbGVjdChsb24sIGxhdCkgJT4lIA0KICAgICAgcmVuYW1lKExvbmcgPSBsb24sIExhdCA9IGxhdCkgJT4lIG11dGF0ZShvYmogPSAiU3VwZXJtYXJrZXRzIiksIA0KICAgIFNZRF9ob3NwaXRhbHMgJT4lIHNlbGVjdChMb25naXR1ZGUsIExhdGl0dWRlKSAlPiUgDQogICAgICByZW5hbWUoTG9uZyA9IExvbmdpdHVkZSwgTGF0ID0gTGF0aXR1ZGUpICU+JSBtdXRhdGUob2JqID0gIkhvc3BpdGFscyIpLCANCiAgICByYmluZChTWURfc3NjaG9vbHMgJT4lIHNlbGVjdChMb25nLCBMYXQpLA0KICAgICAgICAgIFNZRF9wc2Nob29scyAlPiUgc2VsZWN0KExvbmcsIExhdCkpICU+JSBtdXRhdGUob2JqID0gIlNjaG9vbHMiKQ0KICApLCANCiAgc2l6ZSA9IDEsIGFscGhhID0gLjMsIGFlcyh4PUxvbmcsIHk9TGF0LGNvbD1vYmopKSArDQogIGV4cGFuZF9saW1pdHMoeCA9IHRpZHkoU1lEX1BPQSkkbG9uZywgeSA9IHRpZHkoU1lEX1BPQSkkbGF0KSArDQogIHhsaW0oMTUwLjcsMTUxLjQ4KSArIHlsaW0oLTM0LjEsLTMzLjUpICsNCiAgIyBzY2FsZV9maWxsX2dyYWRpZW50KGxvdz0id2hpdGUiLCBoaWdoPURDWzddKSArIA0KICBzY2FsZV9hbHBoYV9jb250aW51b3VzKHJhbmdlID0gYygwLC4zKSkgKyANCiAgZ2djKGZjID0gYygiZGFya3JlZCIsICJkYXJrYmx1ZSIsICJkYXJrb3JhbmdlIiwgImRhcmtncmVlbiIsIA0KICAgICAgICAgICAgICJkYXJrYmx1ZSIsICJyZWQiLCAiZGFya2dyZWVuIiwgIm9yYW5nZSIpKSArIA0KICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTMpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlPSJQT0kiKSkgKyANCiAgdGhlbWVfdm9pZCgpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gYyguOSwuNCksIA0KICAgICAgICAjIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgDQogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNSkpDQpgYGANCg0KIyMgUE9JIGNvdW50IFFBIHsudGFic2V0fQ0KIyMjIEhvc3BpdGFsDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTd9DQpuX3BvaV9ieV9QT0EgJT4lIA0KICBmaWx0ZXIoUE9BX05BTUUxNiAhPSAiVW5rbm93biIpICU+JSANCiAgIyBnYXRoZXIoa2V5LCB2YWx1ZSwgLVBPQV9OQU1FMTYpICU+JSANCiAgc2VsZWN0KFBPQV9OQU1FMTYsIG5faG9zcGl0YWxzKSAlPiUgDQogIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoUE9BX05BTUUxNiwgbl9ob3NwaXRhbHMpKSAlPiUgDQogIHBsb3RfbWFwX1RMKFNZRF9QT0EsICJQT0FfTkFNRTE2IiwgIm5faG9zcGl0YWxzIiwgDQogICAgICAgICAgICAgICJOdW1iZXIgb2YgaG9zcGl0YWxzIGJ5IFBPQSIsIA0KICAgICAgICAgICAgICBzaG93X2NvdW50ID0gVCwgZmlsbF9jb2wgPSAiZGFya3JlZCIpDQpgYGANCg0KIyMjIFNjaG9vbHMNCg0KYGBge3IsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9N30NCm5fcG9pX2J5X1BPQSAlPiUgDQogIGZpbHRlcihQT0FfTkFNRTE2ICE9ICJVbmtub3duIikgJT4lIA0KICAjIGdhdGhlcihrZXksIHZhbHVlLCAtUE9BX05BTUUxNikgJT4lIA0KICBzZWxlY3QoUE9BX05BTUUxNiwgbl9zY2hvb2xzKSAlPiUgDQogIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoUE9BX05BTUUxNiwgbl9zY2hvb2xzKSkgJT4lIA0KICBwbG90X21hcF9UTChTWURfUE9BLCAiUE9BX05BTUUxNiIsICJuX3NjaG9vbHMiLCANCiAgICAgICAgICAgICAgIk51bWJlciBvZiBzY2hvb2xzIGJ5IFBPQSIsIA0KICAgICAgICAgICAgICBzaG93X2NvdW50ID0gVCwgZmlsbF9jb2wgPSAiZGVlcHNreWJsdWUiKQ0KYGBgDQoNCg0KIyMjIFN1cGVybWFya2V0cw0KDQpgYGB7ciwgZmlnLndpZHRoPTkuNSwgZmlnLmhlaWdodD03fQ0Kbl9wb2lfYnlfUE9BICU+JSANCiAgZmlsdGVyKFBPQV9OQU1FMTYgIT0gIlVua25vd24iKSAlPiUgDQogICMgZ2F0aGVyKGtleSwgdmFsdWUsIC1QT0FfTkFNRTE2KSAlPiUgDQogIHNlbGVjdChQT0FfTkFNRTE2LCBuX3N1cGVybWFya2V0cykgJT4lIA0KICBtdXRhdGUoUE9BX05BTUUxNiA9IGZjdF9yZW9yZGVyKFBPQV9OQU1FMTYsIG5fc3VwZXJtYXJrZXRzKSkgJT4lIA0KICBwbG90X21hcF9UTChTWURfUE9BLCAiUE9BX05BTUUxNiIsICJuX3N1cGVybWFya2V0cyIsIA0KICAgICAgICAgICAgICAiTnVtYmVyIG9mIHN1cGVybWFya2V0cyBieSBQT0EiLCANCiAgICAgICAgICAgICAgc2hvd19jb3VudCA9IFQsIGZpbGxfY29sID0gImRhcmtncmVlbiIpDQpgYGANCg0KDQojIyMgU2hvcHBpbmcgY2VudHJlcw0KDQpgYGB7ciwgZmlnLndpZHRoPTkuNSwgZmlnLmhlaWdodD03fQ0Kbl9wb2lfYnlfUE9BICU+JSANCiAgZmlsdGVyKFBPQV9OQU1FMTYgIT0gIlVua25vd24iKSAlPiUgDQogICMgZ2F0aGVyKGtleSwgdmFsdWUsIC1QT0FfTkFNRTE2KSAlPiUgDQogIHNlbGVjdChQT0FfTkFNRTE2LCBuX3Nob3BwaW5nQ2VudHJlcykgJT4lIA0KICBtdXRhdGUoUE9BX05BTUUxNiA9IGZjdF9yZW9yZGVyKFBPQV9OQU1FMTYsIG5fc2hvcHBpbmdDZW50cmVzKSkgJT4lIA0KICBwbG90X21hcF9UTChTWURfUE9BLCAiUE9BX05BTUUxNiIsICJuX3Nob3BwaW5nQ2VudHJlcyIsIA0KICAgICAgICAgICAgICAiTnVtYmVyIG9mIHNob3BwaW5nIGNlbnRyZXMgYnkgUE9BIiwgDQogICAgICAgICAgICAgIHNob3dfY291bnQgPSBULCBmaWxsX2NvbCA9ICJibGFjayIpDQpgYGANCg0KIyMjIFB1YmxpYyB0cmFuc3BvcnRzDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTd9DQpuX3BvaV9ieV9QT0EgJT4lIA0KICBmaWx0ZXIoUE9BX05BTUUxNiAhPSAiVW5rbm93biIpICU+JSANCiAgIyBnYXRoZXIoa2V5LCB2YWx1ZSwgLVBPQV9OQU1FMTYpICU+JSANCiAgc2VsZWN0KFBPQV9OQU1FMTYsIG5fcHVibGljVHJhbnNwb3J0cyApICU+JSANCiAgbXV0YXRlKFBPQV9OQU1FMTYgPSBmY3RfcmVvcmRlcihQT0FfTkFNRTE2LCBuX3B1YmxpY1RyYW5zcG9ydHMgKSkgJT4lIA0KICBwbG90X21hcF9UTChTWURfUE9BLCAiUE9BX05BTUUxNiIsICJuX3B1YmxpY1RyYW5zcG9ydHMiLCANCiAgICAgICAgICAgICAgIk51bWJlciBvZiBwdWJsaWMgdHJhbnNwb3J0cyBieSBQT0EiLCANCiAgICAgICAgICAgICAgc2hvd19jb3VudCA9IFQsIGZpbGxfY29sID0gImRhcmtvcmFuZ2UiKQ0KYGBgDQoNCiMgR3Jhdml0eQ0KIyMgU291dGggRWFzdGVybiBTWUQgKDIwMjYpDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTd9DQooDQpwbG90X2dyYXZpdHlfbWFwX1RMKG5fcG9pX2J5X1BPQSwgIjIwMjYiLCAibl9ob3NwaXRhbHMiKSArIA0KICB4bGltKDE1MS4xLDE1MS4zMykgKyB5bGltKC0zNCwtMzMuNykgfCANCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjAyNiIsICJuX3NjaG9vbHMiKSArIA0KICB4bGltKDE1MS4xLDE1MS4zMykgKyB5bGltKC0zNCwtMzMuNykgfA0KcGxvdF9ncmF2aXR5X21hcF9UTChuX3BvaV9ieV9QT0EsICIyMDI2IiwgIm5fc3VwZXJtYXJrZXRzIikgKyANCiAgeGxpbSgxNTEuMSwxNTEuMzMpICsgeWxpbSgtMzQsLTMzLjcpDQopIC8NCigNCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjAyNiIsICJuX3Nob3BwaW5nQ2VudHJlcyIpICsgDQogIHhsaW0oMTUxLjEsMTUxLjMzKSArIHlsaW0oLTM0LC0zMy43KSB8IA0KcGxvdF9ncmF2aXR5X21hcF9UTChuX3BvaV9ieV9QT0EsICIyMDI2IiwgIm5fcHVibGljVHJhbnNwb3J0cyIpICsgDQogIHhsaW0oMTUxLjEsMTUxLjMzKSArIHlsaW0oLTM0LC0zMy43KSB8IA0Kbl9wb2lfYnlfUE9BICU+JSANCiAgbXV0YXRlKGNvbWJpbmVkX2luZGV4ID0gDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9ob3NwaXRhbHMgKw0KICAgICAgICAgICBub3JtYWxpc2VkX25fc2Nob29scyArDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9zdXBlcm1hcmtldHMgKw0KICAgICAgICAgICBub3JtYWxpc2VkX25fc2hvcHBpbmdDZW50cmVzICsNCiAgICAgICAgICAgbm9ybWFsaXNlZF9uX3B1YmxpY1RyYW5zcG9ydHMNCiAgKSAlPiUgcGxvdF9ncmF2aXR5X21hcF9UTCgiMjAyNiIsICJjb21iaW5lZF9pbmRleCIpICsgDQogIHhsaW0oMTUxLjEsMTUxLjMzKSArIHlsaW0oLTM0LC0zMy43KQ0KKQ0KYGBgDQoNCiMjIFdlc3Rlcm4gU1lEICgyMTQ1KQ0KDQpgYGB7ciwgZmlnLndpZHRoPTkuNSwgZmlnLmhlaWdodD03fQ0KKA0KcGxvdF9ncmF2aXR5X21hcF9UTChuX3BvaV9ieV9QT0EsICIyMTQ1IiwgIm5faG9zcGl0YWxzIikgfCANCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjE0NSIsICJuX3NjaG9vbHMiKSB8DQpwbG90X2dyYXZpdHlfbWFwX1RMKG5fcG9pX2J5X1BPQSwgIjIxNDUiLCAibl9zdXBlcm1hcmtldHMiKQ0KKSAvDQooDQpwbG90X2dyYXZpdHlfbWFwX1RMKG5fcG9pX2J5X1BPQSwgIjIxNDUiLCAibl9zaG9wcGluZ0NlbnRyZXMiKSB8IA0KcGxvdF9ncmF2aXR5X21hcF9UTChuX3BvaV9ieV9QT0EsICIyMTQ1IiwgIm5fcHVibGljVHJhbnNwb3J0cyIpIHwgDQpuX3BvaV9ieV9QT0EgJT4lIA0KICBtdXRhdGUoY29tYmluZWRfaW5kZXggPSANCiAgICAgICAgICAgbm9ybWFsaXNlZF9uX2hvc3BpdGFscyArDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9zY2hvb2xzICsNCiAgICAgICAgICAgbm9ybWFsaXNlZF9uX3N1cGVybWFya2V0cyArDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9zaG9wcGluZ0NlbnRyZXMgKw0KICAgICAgICAgICBub3JtYWxpc2VkX25fcHVibGljVHJhbnNwb3J0cw0KICApICU+JSBwbG90X2dyYXZpdHlfbWFwX1RMKCIyMTQ1IiwgImNvbWJpbmVkX2luZGV4IikNCikNCmBgYA0KDQojIyBOb3RoZXJuIFNZRCAoMjEwNykNCg0KYGBge3IsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9N30NCigNCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjEwNyIsICJuX2hvc3BpdGFscyIpICsgDQogIHhsaW0oMTUxLDE1MS40KSArIHlsaW0oLTMzLjksLTMzLjUpIHwgDQpwbG90X2dyYXZpdHlfbWFwX1RMKG5fcG9pX2J5X1BPQSwgIjIxMDciLCAibl9zY2hvb2xzIikgKyANCiAgeGxpbSgxNTEsMTUxLjQpICsgeWxpbSgtMzMuOSwtMzMuNSkgfA0KcGxvdF9ncmF2aXR5X21hcF9UTChuX3BvaV9ieV9QT0EsICIyMTA3IiwgIm5fc3VwZXJtYXJrZXRzIikgKyANCiAgeGxpbSgxNTEsMTUxLjQpICsgeWxpbSgtMzMuOSwtMzMuNSkNCikgLw0KKA0KcGxvdF9ncmF2aXR5X21hcF9UTChuX3BvaV9ieV9QT0EsICIyMTA3IiwgIm5fc2hvcHBpbmdDZW50cmVzIikgKyANCiAgeGxpbSgxNTEsMTUxLjQpICsgeWxpbSgtMzMuOSwtMzMuNSkgfCANCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjEwNyIsICJuX3B1YmxpY1RyYW5zcG9ydHMiKSArIA0KICB4bGltKDE1MSwxNTEuNCkgKyB5bGltKC0zMy45LC0zMy41KSB8IA0Kbl9wb2lfYnlfUE9BICU+JSANCiAgbXV0YXRlKGNvbWJpbmVkX2luZGV4ID0gDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9ob3NwaXRhbHMgKw0KICAgICAgICAgICBub3JtYWxpc2VkX25fc2Nob29scyArDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9zdXBlcm1hcmtldHMgKw0KICAgICAgICAgICBub3JtYWxpc2VkX25fc2hvcHBpbmdDZW50cmVzICsNCiAgICAgICAgICAgbm9ybWFsaXNlZF9uX3B1YmxpY1RyYW5zcG9ydHMNCiAgKSAlPiUgcGxvdF9ncmF2aXR5X21hcF9UTCgiMjEwNyIsICJjb21iaW5lZF9pbmRleCIpICsgDQogIHhsaW0oMTUxLDE1MS40KSArIHlsaW0oLTMzLjksLTMzLjUpDQopDQpgYGANCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQo=